@bcts/crypto 1.0.0-alpha.8 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,86 +1,55 @@
1
- let __noble_hashes_sha2 = require("@noble/hashes/sha2");
2
- let __noble_hashes_hmac = require("@noble/hashes/hmac");
3
- let __noble_hashes_pbkdf2 = require("@noble/hashes/pbkdf2");
4
- let __noble_hashes_hkdf = require("@noble/hashes/hkdf");
5
- let __noble_ciphers_chacha = require("@noble/ciphers/chacha");
6
- let __noble_curves_ed25519 = require("@noble/curves/ed25519");
7
- let __noble_curves_secp256k1 = require("@noble/curves/secp256k1");
8
- let __bcts_rand = require("@bcts/rand");
9
- let __noble_hashes_scrypt = require("@noble/hashes/scrypt");
10
- let __noble_hashes_argon2 = require("@noble/hashes/argon2");
11
-
12
- //#region src/error.ts
13
- /**
14
- * AEAD-specific error for authentication failures
15
- */
16
- var AeadError = class extends Error {
17
- constructor(message = "AEAD authentication failed") {
18
- super(message);
19
- this.name = "AeadError";
20
- }
21
- };
22
- /**
23
- * Generic crypto error type
24
- */
25
- var CryptoError = class CryptoError extends Error {
26
- cause;
27
- constructor(message, cause) {
28
- super(message);
29
- this.name = "CryptoError";
30
- this.cause = cause;
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __defProp = Object.defineProperty;
4
+ var __exportAll = (all, no_symbols) => {
5
+ let target = {};
6
+ for (var name in all) {
7
+ __defProp(target, name, {
8
+ get: all[name],
9
+ enumerable: true
10
+ });
31
11
  }
32
- /**
33
- * Create a CryptoError for AEAD authentication failures.
34
- *
35
- * @param error - Optional underlying AeadError
36
- * @returns A CryptoError wrapping the AEAD error
37
- */
38
- static aead(error) {
39
- return new CryptoError("AEAD error", error ?? new AeadError());
40
- }
41
- /**
42
- * Create a CryptoError for invalid parameter values.
43
- *
44
- * @param message - Description of the invalid parameter
45
- * @returns A CryptoError describing the invalid parameter
46
- */
47
- static invalidParameter(message) {
48
- return new CryptoError(`Invalid parameter: ${message}`);
12
+ if (!no_symbols) {
13
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
49
14
  }
15
+ return target;
50
16
  };
51
17
 
52
18
  //#endregion
53
- //#region src/memzero.ts
19
+ let _noble_hashes_sha2_js = require("@noble/hashes/sha2.js");
20
+ let _noble_hashes_hmac_js = require("@noble/hashes/hmac.js");
21
+ let _noble_hashes_pbkdf2_js = require("@noble/hashes/pbkdf2.js");
22
+ let _noble_hashes_hkdf_js = require("@noble/hashes/hkdf.js");
23
+ let _noble_ciphers_chacha_js = require("@noble/ciphers/chacha.js");
24
+ let _noble_curves_ed25519_js = require("@noble/curves/ed25519.js");
25
+ let _noble_curves_secp256k1_js = require("@noble/curves/secp256k1.js");
26
+ let _bcts_rand = require("@bcts/rand");
27
+ let _noble_hashes_scrypt_js = require("@noble/hashes/scrypt.js");
28
+ let _noble_hashes_argon2_js = require("@noble/hashes/argon2.js");
29
+
30
+ //#region src/hash.ts
54
31
  /**
55
- * Securely zero out a typed array.
56
- *
57
- * **IMPORTANT: This is a best-effort implementation.** Unlike the Rust reference
58
- * implementation which uses `std::ptr::write_volatile()` for guaranteed volatile
59
- * writes, JavaScript engines and JIT compilers can still potentially optimize
60
- * away these zeroing operations. The check at the end helps prevent optimization,
61
- * but it is not foolproof.
62
- *
63
- * For truly sensitive cryptographic operations, consider using the Web Crypto API's
64
- * `crypto.subtle` with non-extractable keys when possible, as it provides stronger
65
- * guarantees than what can be achieved with pure JavaScript.
32
+ * Copyright © 2023-2026 Blockchain Commons, LLC
33
+ * Copyright © 2025-2026 Parity Technologies
66
34
  *
67
- * This function attempts to prevent the compiler from optimizing away
68
- * the zeroing operation by using a verification check after the zeroing loop.
69
35
  */
70
- function memzero(data) {
71
- const len = data.length;
72
- for (let i = 0; i < len; i++) data[i] = 0;
73
- if (data.length > 0 && data[0] !== 0) throw new Error("memzero failed");
74
- }
75
- /**
76
- * Securely zero out an array of Uint8Arrays.
77
- */
78
- function memzeroVecVecU8(arrays) {
79
- for (const arr of arrays) memzero(arr);
80
- }
81
-
82
- //#endregion
83
- //#region src/hash.ts
36
+ var hash_exports = /* @__PURE__ */ __exportAll({
37
+ CRC32_SIZE: () => 4,
38
+ SHA256_SIZE: () => 32,
39
+ SHA512_SIZE: () => 64,
40
+ crc32: () => crc32,
41
+ crc32Data: () => crc32Data,
42
+ crc32DataOpt: () => crc32DataOpt,
43
+ doubleSha256: () => doubleSha256,
44
+ hkdfHmacSha256: () => hkdfHmacSha256,
45
+ hkdfHmacSha512: () => hkdfHmacSha512,
46
+ hmacSha256: () => hmacSha256,
47
+ hmacSha512: () => hmacSha512,
48
+ pbkdf2HmacSha256: () => pbkdf2HmacSha256,
49
+ pbkdf2HmacSha512: () => pbkdf2HmacSha512,
50
+ sha256: () => sha256,
51
+ sha512: () => sha512
52
+ });
84
53
  const CRC32_SIZE = 4;
85
54
  const SHA256_SIZE = 32;
86
55
  const SHA512_SIZE = 64;
@@ -119,7 +88,7 @@ function crc32DataOpt(data, littleEndian) {
119
88
  * Calculate SHA-256 hash
120
89
  */
121
90
  function sha256(data) {
122
- return (0, __noble_hashes_sha2.sha256)(data);
91
+ return (0, _noble_hashes_sha2_js.sha256)(data);
123
92
  }
124
93
  /**
125
94
  * Calculate double SHA-256 hash (SHA-256 of SHA-256)
@@ -132,25 +101,25 @@ function doubleSha256(message) {
132
101
  * Calculate SHA-512 hash
133
102
  */
134
103
  function sha512(data) {
135
- return (0, __noble_hashes_sha2.sha512)(data);
104
+ return (0, _noble_hashes_sha2_js.sha512)(data);
136
105
  }
137
106
  /**
138
107
  * Calculate HMAC-SHA-256
139
108
  */
140
109
  function hmacSha256(key, message) {
141
- return (0, __noble_hashes_hmac.hmac)(__noble_hashes_sha2.sha256, key, message);
110
+ return (0, _noble_hashes_hmac_js.hmac)(_noble_hashes_sha2_js.sha256, key, message);
142
111
  }
143
112
  /**
144
113
  * Calculate HMAC-SHA-512
145
114
  */
146
115
  function hmacSha512(key, message) {
147
- return (0, __noble_hashes_hmac.hmac)(__noble_hashes_sha2.sha512, key, message);
116
+ return (0, _noble_hashes_hmac_js.hmac)(_noble_hashes_sha2_js.sha512, key, message);
148
117
  }
149
118
  /**
150
119
  * Derive a key using PBKDF2 with HMAC-SHA-256
151
120
  */
152
121
  function pbkdf2HmacSha256(password, salt, iterations, keyLen) {
153
- return (0, __noble_hashes_pbkdf2.pbkdf2)(__noble_hashes_sha2.sha256, password, salt, {
122
+ return (0, _noble_hashes_pbkdf2_js.pbkdf2)(_noble_hashes_sha2_js.sha256, password, salt, {
154
123
  c: iterations,
155
124
  dkLen: keyLen
156
125
  });
@@ -159,7 +128,7 @@ function pbkdf2HmacSha256(password, salt, iterations, keyLen) {
159
128
  * Derive a key using PBKDF2 with HMAC-SHA-512
160
129
  */
161
130
  function pbkdf2HmacSha512(password, salt, iterations, keyLen) {
162
- return (0, __noble_hashes_pbkdf2.pbkdf2)(__noble_hashes_sha2.sha512, password, salt, {
131
+ return (0, _noble_hashes_pbkdf2_js.pbkdf2)(_noble_hashes_sha2_js.sha512, password, salt, {
163
132
  c: iterations,
164
133
  dkLen: keyLen
165
134
  });
@@ -168,17 +137,112 @@ function pbkdf2HmacSha512(password, salt, iterations, keyLen) {
168
137
  * Derive a key using HKDF with HMAC-SHA-256
169
138
  */
170
139
  function hkdfHmacSha256(keyMaterial, salt, keyLen) {
171
- return (0, __noble_hashes_hkdf.hkdf)(__noble_hashes_sha2.sha256, keyMaterial, salt, void 0, keyLen);
140
+ return (0, _noble_hashes_hkdf_js.hkdf)(_noble_hashes_sha2_js.sha256, keyMaterial, salt, void 0, keyLen);
172
141
  }
173
142
  /**
174
143
  * Derive a key using HKDF with HMAC-SHA-512
175
144
  */
176
145
  function hkdfHmacSha512(keyMaterial, salt, keyLen) {
177
- return (0, __noble_hashes_hkdf.hkdf)(__noble_hashes_sha2.sha512, keyMaterial, salt, void 0, keyLen);
146
+ return (0, _noble_hashes_hkdf_js.hkdf)(_noble_hashes_sha2_js.sha512, keyMaterial, salt, void 0, keyLen);
147
+ }
148
+
149
+ //#endregion
150
+ //#region src/error.ts
151
+ /**
152
+ * Copyright © 2023-2026 Blockchain Commons, LLC
153
+ * Copyright © 2025-2026 Parity Technologies
154
+ *
155
+ */
156
+ /**
157
+ * AEAD-specific error for authentication failures
158
+ */
159
+ var AeadError = class extends Error {
160
+ constructor(message = "AEAD authentication failed") {
161
+ super(message);
162
+ this.name = "AeadError";
163
+ }
164
+ };
165
+ /**
166
+ * Generic crypto error type
167
+ */
168
+ var CryptoError = class CryptoError extends Error {
169
+ cause;
170
+ constructor(message, cause) {
171
+ super(message);
172
+ this.name = "CryptoError";
173
+ this.cause = cause;
174
+ }
175
+ /**
176
+ * Create a CryptoError for AEAD authentication failures.
177
+ *
178
+ * @param error - Optional underlying AeadError
179
+ * @returns A CryptoError wrapping the AEAD error
180
+ */
181
+ static aead(error) {
182
+ return new CryptoError("AEAD error", error ?? new AeadError());
183
+ }
184
+ /**
185
+ * Create a CryptoError for invalid parameter values.
186
+ *
187
+ * **TS-specific.** Rust's `bc_crypto::Error` enum has no
188
+ * `InvalidParameter` variant; size validation in Rust is enforced at
189
+ * compile time via fixed-size array references (e.g. `&[u8; 32]`) or
190
+ * via `panic!`/`expect(...)` for runtime checks. The TS port has no
191
+ * fixed-size array types, so it surfaces those same conditions through
192
+ * a thrown `CryptoError.invalidParameter(...)`. Catching this is
193
+ * equivalent to defensive guards around an `expect`-style panic on the
194
+ * Rust side.
195
+ *
196
+ * @param message - Description of the invalid parameter
197
+ * @returns A CryptoError describing the invalid parameter
198
+ */
199
+ static invalidParameter(message) {
200
+ return new CryptoError(`Invalid parameter: ${message}`);
201
+ }
202
+ };
203
+
204
+ //#endregion
205
+ //#region src/memzero.ts
206
+ /**
207
+ * Securely zero out a typed array.
208
+ *
209
+ * Mirrors Rust `bc_crypto::memzero<T>(s: &mut [T])`. The Rust impl uses
210
+ * `std::ptr::write_volatile()` to guarantee the writes survive optimization;
211
+ * JavaScript has no equivalent primitive, so this is **best-effort** — JIT
212
+ * compilers may still elide the loop, though the post-hoc verification
213
+ * check forces the engine to keep the writes observable.
214
+ *
215
+ * For truly sensitive cryptographic operations, consider using the Web
216
+ * Crypto API's `crypto.subtle` with non-extractable keys when possible, as
217
+ * it provides stronger guarantees than what can be achieved with pure
218
+ * JavaScript.
219
+ *
220
+ * Accepts any of the standard numeric typed arrays — `Uint8Array`,
221
+ * `Uint8ClampedArray`, `Uint16Array`, `Uint32Array`, `Int8Array`,
222
+ * `Int16Array`, `Int32Array`, `Float32Array`, `Float64Array` — matching
223
+ * Rust's generic `&mut [T]`. (`BigInt64Array` / `BigUint64Array` are
224
+ * excluded because their elements are `bigint`, not `number`; if that
225
+ * support is needed, add a dedicated overload.)
226
+ */
227
+ function memzero(data) {
228
+ const len = data.length;
229
+ for (let i = 0; i < len; i++) data[i] = 0;
230
+ if (data.length > 0 && data[0] !== 0) throw new Error("memzero failed");
231
+ }
232
+ /**
233
+ * Securely zero out an array of Uint8Arrays.
234
+ */
235
+ function memzeroVecVecU8(arrays) {
236
+ for (const arr of arrays) memzero(arr);
178
237
  }
179
238
 
180
239
  //#endregion
181
240
  //#region src/symmetric-encryption.ts
241
+ /**
242
+ * Copyright © 2023-2026 Blockchain Commons, LLC
243
+ * Copyright © 2025-2026 Parity Technologies
244
+ *
245
+ */
182
246
  const SYMMETRIC_KEY_SIZE = 32;
183
247
  const SYMMETRIC_NONCE_SIZE = 12;
184
248
  const SYMMETRIC_AUTH_SIZE = 16;
@@ -213,10 +277,10 @@ function aeadChaCha20Poly1305Encrypt(plaintext, key, nonce) {
213
277
  * @throws {CryptoError} If key is not 32 bytes or nonce is not 12 bytes
214
278
  */
215
279
  function aeadChaCha20Poly1305EncryptWithAad(plaintext, key, nonce, aad) {
216
- if (key.length !== SYMMETRIC_KEY_SIZE) throw CryptoError.invalidParameter(`Key must be ${SYMMETRIC_KEY_SIZE} bytes`);
217
- if (nonce.length !== SYMMETRIC_NONCE_SIZE) throw CryptoError.invalidParameter(`Nonce must be ${SYMMETRIC_NONCE_SIZE} bytes`);
218
- const sealed = (0, __noble_ciphers_chacha.chacha20poly1305)(key, nonce, aad).encrypt(plaintext);
219
- return [sealed.slice(0, sealed.length - SYMMETRIC_AUTH_SIZE), sealed.slice(sealed.length - SYMMETRIC_AUTH_SIZE)];
280
+ if (key.length !== 32) throw CryptoError.invalidParameter(`Key must be ${32} bytes`);
281
+ if (nonce.length !== 12) throw CryptoError.invalidParameter(`Nonce must be ${12} bytes`);
282
+ const sealed = (0, _noble_ciphers_chacha_js.chacha20poly1305)(key, nonce, aad).encrypt(plaintext);
283
+ return [sealed.slice(0, sealed.length - 16), sealed.slice(sealed.length - 16)];
220
284
  }
221
285
  /**
222
286
  * Decrypt data using ChaCha20-Poly1305 AEAD cipher.
@@ -245,14 +309,14 @@ function aeadChaCha20Poly1305Decrypt(ciphertext, key, nonce, authTag) {
245
309
  * @throws {CryptoError} If authentication fails (tampered data, wrong key/nonce, or AAD mismatch)
246
310
  */
247
311
  function aeadChaCha20Poly1305DecryptWithAad(ciphertext, key, nonce, aad, authTag) {
248
- if (key.length !== SYMMETRIC_KEY_SIZE) throw CryptoError.invalidParameter(`Key must be ${SYMMETRIC_KEY_SIZE} bytes`);
249
- if (nonce.length !== SYMMETRIC_NONCE_SIZE) throw CryptoError.invalidParameter(`Nonce must be ${SYMMETRIC_NONCE_SIZE} bytes`);
250
- if (authTag.length !== SYMMETRIC_AUTH_SIZE) throw CryptoError.invalidParameter(`Auth tag must be ${SYMMETRIC_AUTH_SIZE} bytes`);
312
+ if (key.length !== 32) throw CryptoError.invalidParameter(`Key must be ${32} bytes`);
313
+ if (nonce.length !== 12) throw CryptoError.invalidParameter(`Nonce must be ${12} bytes`);
314
+ if (authTag.length !== 16) throw CryptoError.invalidParameter(`Auth tag must be ${16} bytes`);
251
315
  const sealed = new Uint8Array(ciphertext.length + authTag.length);
252
316
  sealed.set(ciphertext);
253
317
  sealed.set(authTag, ciphertext.length);
254
318
  try {
255
- return (0, __noble_ciphers_chacha.chacha20poly1305)(key, nonce, aad).decrypt(sealed);
319
+ return (0, _noble_ciphers_chacha_js.chacha20poly1305)(key, nonce, aad).decrypt(sealed);
256
320
  } catch (error) {
257
321
  const aeadError = new AeadError(`Decryption failed: ${error instanceof Error ? error.message : "authentication error"}`);
258
322
  throw CryptoError.aead(aeadError);
@@ -261,8 +325,11 @@ function aeadChaCha20Poly1305DecryptWithAad(ciphertext, key, nonce, aad, authTag
261
325
 
262
326
  //#endregion
263
327
  //#region src/public-key-encryption.ts
264
- const GENERIC_PRIVATE_KEY_SIZE = 32;
265
- const GENERIC_PUBLIC_KEY_SIZE = 32;
328
+ /**
329
+ * Copyright © 2023-2026 Blockchain Commons, LLC
330
+ * Copyright © 2025-2026 Parity Technologies
331
+ *
332
+ */
266
333
  const X25519_PRIVATE_KEY_SIZE = 32;
267
334
  const X25519_PUBLIC_KEY_SIZE = 32;
268
335
  /**
@@ -270,7 +337,7 @@ const X25519_PUBLIC_KEY_SIZE = 32;
270
337
  * Uses HKDF with "agreement" as domain separation salt.
271
338
  */
272
339
  function deriveAgreementPrivateKey(keyMaterial) {
273
- return hkdfHmacSha256(keyMaterial, new TextEncoder().encode("agreement"), X25519_PRIVATE_KEY_SIZE);
340
+ return hkdfHmacSha256(keyMaterial, new TextEncoder().encode("agreement"), 32);
274
341
  }
275
342
  /**
276
343
  * Derive a signing private key from key material.
@@ -283,35 +350,52 @@ function deriveSigningPrivateKey(keyMaterial) {
283
350
  * Generate a new random X25519 private key.
284
351
  */
285
352
  function x25519NewPrivateKeyUsing(rng) {
286
- return rng.randomData(X25519_PRIVATE_KEY_SIZE);
353
+ return rng.randomData(32);
287
354
  }
288
355
  /**
289
356
  * Derive an X25519 public key from a private key.
290
357
  */
291
358
  function x25519PublicKeyFromPrivateKey(privateKey) {
292
- if (privateKey.length !== X25519_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${X25519_PRIVATE_KEY_SIZE} bytes`);
293
- return __noble_curves_ed25519.x25519.getPublicKey(privateKey);
359
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
360
+ return _noble_curves_ed25519_js.x25519.getPublicKey(privateKey);
294
361
  }
362
+ const SYMMETRIC_KEY_SIZE$1 = 32;
295
363
  /**
296
- * Compute a shared secret using X25519 key agreement (ECDH).
364
+ * Compute a shared symmetric key using X25519 key agreement (ECDH).
297
365
  *
298
- * **Security Note**: The resulting shared secret should be used with a KDF
299
- * (like HKDF) before using it as an encryption key. Never use the raw
300
- * shared secret directly for encryption.
366
+ * This function performs X25519 Diffie-Hellman key agreement and then
367
+ * derives a symmetric key using HKDF-SHA256 with "agreement" as the salt.
368
+ * This matches the Rust bc-crypto implementation for cross-platform compatibility.
369
+ *
370
+ * **Low-order public key handling.** The underlying `@noble/curves` X25519
371
+ * implementation rejects low-order public keys (where the u-coordinate is
372
+ * `0`) by throwing `'invalid private or public key received'`. Rust's
373
+ * `x25519-dalek` (v2.0-rc.2) instead silently produces the all-zero shared
374
+ * secret. This means an adversarial low-order public key fed in via TS
375
+ * surfaces as an exception, while in Rust it would yield an HKDF-derived
376
+ * key from a zero shared secret. For honest inputs both implementations
377
+ * produce byte-identical results; the TS port's stricter behaviour is a
378
+ * security improvement, not a parity bug.
301
379
  *
302
380
  * @param x25519Private - 32-byte X25519 private key
303
381
  * @param x25519Public - 32-byte X25519 public key from the other party
304
- * @returns 32-byte shared secret
382
+ * @returns 32-byte derived symmetric key
305
383
  * @throws {Error} If private key is not 32 bytes or public key is not 32 bytes
384
+ * @throws {Error} If the public key is low-order (`@noble/curves`-specific guard)
306
385
  */
307
386
  function x25519SharedKey(x25519Private, x25519Public) {
308
- if (x25519Private.length !== X25519_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${X25519_PRIVATE_KEY_SIZE} bytes`);
309
- if (x25519Public.length !== X25519_PUBLIC_KEY_SIZE) throw new Error(`Public key must be ${X25519_PUBLIC_KEY_SIZE} bytes`);
310
- return __noble_curves_ed25519.x25519.getSharedSecret(x25519Private, x25519Public);
387
+ if (x25519Private.length !== 32) throw new Error(`Private key must be ${32} bytes`);
388
+ if (x25519Public.length !== 32) throw new Error(`Public key must be ${32} bytes`);
389
+ return hkdfHmacSha256(_noble_curves_ed25519_js.x25519.getSharedSecret(x25519Private, x25519Public), new TextEncoder().encode("agreement"), SYMMETRIC_KEY_SIZE$1);
311
390
  }
312
391
 
313
392
  //#endregion
314
393
  //#region src/ecdsa-keys.ts
394
+ /**
395
+ * Copyright © 2023-2026 Blockchain Commons, LLC
396
+ * Copyright © 2025-2026 Parity Technologies
397
+ *
398
+ */
315
399
  const ECDSA_PRIVATE_KEY_SIZE = 32;
316
400
  const ECDSA_PUBLIC_KEY_SIZE = 33;
317
401
  const ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE = 65;
@@ -326,28 +410,28 @@ const SCHNORR_PUBLIC_KEY_SIZE = 32;
326
410
  * the key is used.
327
411
  */
328
412
  function ecdsaNewPrivateKeyUsing(rng) {
329
- return rng.randomData(ECDSA_PRIVATE_KEY_SIZE);
413
+ return rng.randomData(32);
330
414
  }
331
415
  /**
332
416
  * Derive a compressed ECDSA public key from a private key.
333
417
  */
334
418
  function ecdsaPublicKeyFromPrivateKey(privateKey) {
335
- if (privateKey.length !== ECDSA_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ECDSA_PRIVATE_KEY_SIZE} bytes`);
336
- return __noble_curves_secp256k1.secp256k1.getPublicKey(privateKey, true);
419
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
420
+ return _noble_curves_secp256k1_js.secp256k1.getPublicKey(privateKey, true);
337
421
  }
338
422
  /**
339
423
  * Decompress a compressed public key to uncompressed format.
340
424
  */
341
425
  function ecdsaDecompressPublicKey(compressed) {
342
- if (compressed.length !== ECDSA_PUBLIC_KEY_SIZE) throw new Error(`Compressed public key must be ${ECDSA_PUBLIC_KEY_SIZE} bytes`);
343
- return __noble_curves_secp256k1.secp256k1.ProjectivePoint.fromHex(compressed).toRawBytes(false);
426
+ if (compressed.length !== 33) throw new Error(`Compressed public key must be ${33} bytes`);
427
+ return _noble_curves_secp256k1_js.secp256k1.Point.fromBytes(compressed).toBytes(false);
344
428
  }
345
429
  /**
346
430
  * Compress an uncompressed public key.
347
431
  */
348
432
  function ecdsaCompressPublicKey(uncompressed) {
349
- if (uncompressed.length !== ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE) throw new Error(`Uncompressed public key must be ${ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE} bytes`);
350
- return __noble_curves_secp256k1.secp256k1.ProjectivePoint.fromHex(uncompressed).toRawBytes(true);
433
+ if (uncompressed.length !== 65) throw new Error(`Uncompressed public key must be ${65} bytes`);
434
+ return _noble_curves_secp256k1_js.secp256k1.Point.fromBytes(uncompressed).toBytes(true);
351
435
  }
352
436
  /**
353
437
  * Derive an ECDSA private key from key material using HKDF.
@@ -356,20 +440,25 @@ function ecdsaCompressPublicKey(uncompressed) {
356
440
  * matching the Rust reference implementation behavior.
357
441
  */
358
442
  function ecdsaDerivePrivateKey(keyMaterial) {
359
- return hkdfHmacSha256(keyMaterial, new TextEncoder().encode("signing"), ECDSA_PRIVATE_KEY_SIZE);
443
+ return hkdfHmacSha256(keyMaterial, new TextEncoder().encode("signing"), 32);
360
444
  }
361
445
  /**
362
446
  * Extract the x-only (Schnorr) public key from a private key.
363
447
  * This is used for BIP-340 Schnorr signatures.
364
448
  */
365
449
  function schnorrPublicKeyFromPrivateKey(privateKey) {
366
- if (privateKey.length !== ECDSA_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ECDSA_PRIVATE_KEY_SIZE} bytes`);
367
- return __noble_curves_secp256k1.secp256k1.getPublicKey(privateKey, false).slice(1, 33);
450
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
451
+ return _noble_curves_secp256k1_js.secp256k1.getPublicKey(privateKey, false).slice(1, 33);
368
452
  }
369
453
 
370
454
  //#endregion
371
455
  //#region src/ecdsa-signing.ts
372
456
  /**
457
+ * Copyright © 2023-2026 Blockchain Commons, LLC
458
+ * Copyright © 2025-2026 Parity Technologies
459
+ *
460
+ */
461
+ /**
373
462
  * Sign a message using ECDSA with secp256k1.
374
463
  *
375
464
  * The message is hashed with double SHA-256 before signing (Bitcoin standard).
@@ -384,9 +473,9 @@ function schnorrPublicKeyFromPrivateKey(privateKey) {
384
473
  * @throws {Error} If private key is not 32 bytes
385
474
  */
386
475
  function ecdsaSign(privateKey, message) {
387
- if (privateKey.length !== ECDSA_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ECDSA_PRIVATE_KEY_SIZE} bytes`);
476
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
388
477
  const messageHash = doubleSha256(message);
389
- return __noble_curves_secp256k1.secp256k1.sign(messageHash, privateKey).toCompactRawBytes();
478
+ return _noble_curves_secp256k1_js.secp256k1.sign(messageHash, privateKey, { prehash: false });
390
479
  }
391
480
  /**
392
481
  * Verify an ECDSA signature with secp256k1.
@@ -400,11 +489,11 @@ function ecdsaSign(privateKey, message) {
400
489
  * @throws {Error} If public key is not 33 bytes or signature is not 64 bytes
401
490
  */
402
491
  function ecdsaVerify(publicKey, signature, message) {
403
- if (publicKey.length !== ECDSA_PUBLIC_KEY_SIZE) throw new Error(`Public key must be ${ECDSA_PUBLIC_KEY_SIZE} bytes`);
404
- if (signature.length !== ECDSA_SIGNATURE_SIZE) throw new Error(`Signature must be ${ECDSA_SIGNATURE_SIZE} bytes`);
492
+ if (publicKey.length !== 33) throw new Error(`Public key must be ${33} bytes`);
493
+ if (signature.length !== 64) throw new Error(`Signature must be ${64} bytes`);
405
494
  try {
406
495
  const messageHash = doubleSha256(message);
407
- return __noble_curves_secp256k1.secp256k1.verify(signature, messageHash, publicKey);
496
+ return _noble_curves_secp256k1_js.secp256k1.verify(signature, messageHash, publicKey, { prehash: false });
408
497
  } catch {
409
498
  return false;
410
499
  }
@@ -412,6 +501,11 @@ function ecdsaVerify(publicKey, signature, message) {
412
501
 
413
502
  //#endregion
414
503
  //#region src/schnorr-signing.ts
504
+ /**
505
+ * Copyright © 2023-2026 Blockchain Commons, LLC
506
+ * Copyright © 2025-2026 Parity Technologies
507
+ *
508
+ */
415
509
  const SCHNORR_SIGNATURE_SIZE = 64;
416
510
  /**
417
511
  * Sign a message using Schnorr signature (BIP-340).
@@ -422,7 +516,7 @@ const SCHNORR_SIGNATURE_SIZE = 64;
422
516
  * @returns 64-byte Schnorr signature
423
517
  */
424
518
  function schnorrSign(ecdsaPrivateKey, message) {
425
- return schnorrSignUsing(ecdsaPrivateKey, message, new __bcts_rand.SecureRandomNumberGenerator());
519
+ return schnorrSignUsing(ecdsaPrivateKey, message, new _bcts_rand.SecureRandomNumberGenerator());
426
520
  }
427
521
  /**
428
522
  * Sign a message using Schnorr signature with a custom RNG.
@@ -445,9 +539,9 @@ function schnorrSignUsing(ecdsaPrivateKey, message, rng) {
445
539
  * @returns 64-byte Schnorr signature
446
540
  */
447
541
  function schnorrSignWithAuxRand(ecdsaPrivateKey, message, auxRand) {
448
- if (ecdsaPrivateKey.length !== ECDSA_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ECDSA_PRIVATE_KEY_SIZE} bytes`);
542
+ if (ecdsaPrivateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
449
543
  if (auxRand.length !== 32) throw new Error("Auxiliary randomness must be 32 bytes");
450
- return __noble_curves_secp256k1.schnorr.sign(message, ecdsaPrivateKey, auxRand);
544
+ return _noble_curves_secp256k1_js.schnorr.sign(message, ecdsaPrivateKey, auxRand);
451
545
  }
452
546
  /**
453
547
  * Verify a Schnorr signature (BIP-340).
@@ -458,10 +552,10 @@ function schnorrSignWithAuxRand(ecdsaPrivateKey, message, auxRand) {
458
552
  * @returns true if signature is valid
459
553
  */
460
554
  function schnorrVerify(schnorrPublicKey, signature, message) {
461
- if (schnorrPublicKey.length !== SCHNORR_PUBLIC_KEY_SIZE) throw new Error(`Public key must be ${SCHNORR_PUBLIC_KEY_SIZE} bytes`);
462
- if (signature.length !== SCHNORR_SIGNATURE_SIZE) throw new Error(`Signature must be ${SCHNORR_SIGNATURE_SIZE} bytes`);
555
+ if (schnorrPublicKey.length !== 32) throw new Error(`Public key must be ${32} bytes`);
556
+ if (signature.length !== 64) throw new Error(`Signature must be ${64} bytes`);
463
557
  try {
464
- return __noble_curves_secp256k1.schnorr.verify(signature, message, schnorrPublicKey);
558
+ return _noble_curves_secp256k1_js.schnorr.verify(signature, message, schnorrPublicKey);
465
559
  } catch {
466
560
  return false;
467
561
  }
@@ -469,6 +563,11 @@ function schnorrVerify(schnorrPublicKey, signature, message) {
469
563
 
470
564
  //#endregion
471
565
  //#region src/ed25519-signing.ts
566
+ /**
567
+ * Copyright © 2023-2026 Blockchain Commons, LLC
568
+ * Copyright © 2025-2026 Parity Technologies
569
+ *
570
+ */
472
571
  const ED25519_PUBLIC_KEY_SIZE = 32;
473
572
  const ED25519_PRIVATE_KEY_SIZE = 32;
474
573
  const ED25519_SIGNATURE_SIZE = 64;
@@ -476,14 +575,14 @@ const ED25519_SIGNATURE_SIZE = 64;
476
575
  * Generate a new random Ed25519 private key.
477
576
  */
478
577
  function ed25519NewPrivateKeyUsing(rng) {
479
- return rng.randomData(ED25519_PRIVATE_KEY_SIZE);
578
+ return rng.randomData(32);
480
579
  }
481
580
  /**
482
581
  * Derive an Ed25519 public key from a private key.
483
582
  */
484
583
  function ed25519PublicKeyFromPrivateKey(privateKey) {
485
- if (privateKey.length !== ED25519_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ED25519_PRIVATE_KEY_SIZE} bytes`);
486
- return __noble_curves_ed25519.ed25519.getPublicKey(privateKey);
584
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
585
+ return _noble_curves_ed25519_js.ed25519.getPublicKey(privateKey);
487
586
  }
488
587
  /**
489
588
  * Sign a message using Ed25519.
@@ -497,8 +596,8 @@ function ed25519PublicKeyFromPrivateKey(privateKey) {
497
596
  * @throws {Error} If private key is not 32 bytes
498
597
  */
499
598
  function ed25519Sign(privateKey, message) {
500
- if (privateKey.length !== ED25519_PRIVATE_KEY_SIZE) throw new Error(`Private key must be ${ED25519_PRIVATE_KEY_SIZE} bytes`);
501
- return __noble_curves_ed25519.ed25519.sign(message, privateKey);
599
+ if (privateKey.length !== 32) throw new Error(`Private key must be ${32} bytes`);
600
+ return _noble_curves_ed25519_js.ed25519.sign(message, privateKey);
502
601
  }
503
602
  /**
504
603
  * Verify an Ed25519 signature.
@@ -510,10 +609,10 @@ function ed25519Sign(privateKey, message) {
510
609
  * @throws {Error} If public key is not 32 bytes or signature is not 64 bytes
511
610
  */
512
611
  function ed25519Verify(publicKey, message, signature) {
513
- if (publicKey.length !== ED25519_PUBLIC_KEY_SIZE) throw new Error(`Public key must be ${ED25519_PUBLIC_KEY_SIZE} bytes`);
514
- if (signature.length !== ED25519_SIGNATURE_SIZE) throw new Error(`Signature must be ${ED25519_SIGNATURE_SIZE} bytes`);
612
+ if (publicKey.length !== 32) throw new Error(`Public key must be ${32} bytes`);
613
+ if (signature.length !== 64) throw new Error(`Signature must be ${64} bytes`);
515
614
  try {
516
- return __noble_curves_ed25519.ed25519.verify(signature, message, publicKey);
615
+ return _noble_curves_ed25519_js.ed25519.verify(signature, message, publicKey);
517
616
  } catch {
518
617
  return false;
519
618
  }
@@ -522,8 +621,16 @@ function ed25519Verify(publicKey, message, signature) {
522
621
  //#endregion
523
622
  //#region src/scrypt.ts
524
623
  /**
624
+ * Copyright © 2023-2026 Blockchain Commons, LLC
625
+ * Copyright © 2025-2026 Parity Technologies
626
+ *
627
+ */
628
+ /**
525
629
  * Derive a key using Scrypt with recommended parameters.
526
- * Uses N=2^15 (32768), r=8, p=1 as recommended defaults.
630
+ *
631
+ * Mirrors Rust `bc_crypto::scrypt` which calls `scrypt::Params::recommended()`.
632
+ * The recommended parameters per the upstream `scrypt` crate are
633
+ * `log_n = 17` (N = 2^17 = 131072), `r = 8`, `p = 1`.
527
634
  *
528
635
  * @param password - Password or passphrase
529
636
  * @param salt - Salt value
@@ -531,7 +638,7 @@ function ed25519Verify(publicKey, message, signature) {
531
638
  * @returns Derived key
532
639
  */
533
640
  function scrypt(password, salt, outputLen) {
534
- return scryptOpt(password, salt, outputLen, 15, 8, 1);
641
+ return scryptOpt(password, salt, outputLen, 17, 8, 1);
535
642
  }
536
643
  /**
537
644
  * Derive a key using Scrypt with custom parameters.
@@ -548,7 +655,7 @@ function scryptOpt(password, salt, outputLen, logN, r, p) {
548
655
  if (logN >= 64) throw new Error("logN must be <64");
549
656
  if (r === 0) throw new Error("r must be >0");
550
657
  if (p === 0) throw new Error("p must be >0");
551
- return (0, __noble_hashes_scrypt.scrypt)(password, salt, {
658
+ return (0, _noble_hashes_scrypt_js.scrypt)(password, salt, {
552
659
  N: 1 << logN,
553
660
  r,
554
661
  p,
@@ -559,15 +666,24 @@ function scryptOpt(password, salt, outputLen, logN, r, p) {
559
666
  //#endregion
560
667
  //#region src/argon.ts
561
668
  /**
669
+ * Copyright © 2023-2026 Blockchain Commons, LLC
670
+ * Copyright © 2025-2026 Parity Technologies
671
+ *
672
+ */
673
+ /**
562
674
  * Derive a key using Argon2id with default parameters.
563
675
  *
676
+ * Mirrors Rust `bc_crypto::argon2id` which calls `Argon2::default()`. The
677
+ * upstream `argon2` crate's defaults are `t = 2` iterations, `m = 19 * 1024
678
+ * = 19456` KiB of memory, `p = 1` lane (per `argon2-0.5.x/src/params.rs`).
679
+ *
564
680
  * @param password - Password or passphrase
565
681
  * @param salt - Salt value (must be at least 8 bytes)
566
682
  * @param outputLen - Desired output length
567
683
  * @returns Derived key
568
684
  */
569
- function argon2idHash(password, salt, outputLen) {
570
- return argon2idHashOpt(password, salt, outputLen, 3, 65536, 4);
685
+ function argon2id(password, salt, outputLen) {
686
+ return argon2idHashOpt(password, salt, outputLen, 2, 19456, 1);
571
687
  }
572
688
  /**
573
689
  * Derive a key using Argon2id with custom parameters.
@@ -581,7 +697,7 @@ function argon2idHash(password, salt, outputLen) {
581
697
  * @returns Derived key
582
698
  */
583
699
  function argon2idHashOpt(password, salt, outputLen, iterations, memory, parallelism) {
584
- return (0, __noble_hashes_argon2.argon2id)(password, salt, {
700
+ return (0, _noble_hashes_argon2_js.argon2id)(password, salt, {
585
701
  t: iterations,
586
702
  m: memory,
587
703
  p: parallelism,
@@ -601,8 +717,6 @@ exports.ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE = ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE;
601
717
  exports.ED25519_PRIVATE_KEY_SIZE = ED25519_PRIVATE_KEY_SIZE;
602
718
  exports.ED25519_PUBLIC_KEY_SIZE = ED25519_PUBLIC_KEY_SIZE;
603
719
  exports.ED25519_SIGNATURE_SIZE = ED25519_SIGNATURE_SIZE;
604
- exports.GENERIC_PRIVATE_KEY_SIZE = GENERIC_PRIVATE_KEY_SIZE;
605
- exports.GENERIC_PUBLIC_KEY_SIZE = GENERIC_PUBLIC_KEY_SIZE;
606
720
  exports.SCHNORR_PUBLIC_KEY_SIZE = SCHNORR_PUBLIC_KEY_SIZE;
607
721
  exports.SCHNORR_SIGNATURE_SIZE = SCHNORR_SIGNATURE_SIZE;
608
722
  exports.SHA256_SIZE = SHA256_SIZE;
@@ -616,11 +730,7 @@ exports.aeadChaCha20Poly1305Decrypt = aeadChaCha20Poly1305Decrypt;
616
730
  exports.aeadChaCha20Poly1305DecryptWithAad = aeadChaCha20Poly1305DecryptWithAad;
617
731
  exports.aeadChaCha20Poly1305Encrypt = aeadChaCha20Poly1305Encrypt;
618
732
  exports.aeadChaCha20Poly1305EncryptWithAad = aeadChaCha20Poly1305EncryptWithAad;
619
- exports.argon2idHash = argon2idHash;
620
- exports.argon2idHashOpt = argon2idHashOpt;
621
- exports.crc32 = crc32;
622
- exports.crc32Data = crc32Data;
623
- exports.crc32DataOpt = crc32DataOpt;
733
+ exports.argon2id = argon2id;
624
734
  exports.deriveAgreementPrivateKey = deriveAgreementPrivateKey;
625
735
  exports.deriveSigningPrivateKey = deriveSigningPrivateKey;
626
736
  exports.doubleSha256 = doubleSha256;
@@ -635,14 +745,18 @@ exports.ed25519NewPrivateKeyUsing = ed25519NewPrivateKeyUsing;
635
745
  exports.ed25519PublicKeyFromPrivateKey = ed25519PublicKeyFromPrivateKey;
636
746
  exports.ed25519Sign = ed25519Sign;
637
747
  exports.ed25519Verify = ed25519Verify;
748
+ Object.defineProperty(exports, 'hash', {
749
+ enumerable: true,
750
+ get: function () {
751
+ return hash_exports;
752
+ }
753
+ });
638
754
  exports.hkdfHmacSha256 = hkdfHmacSha256;
639
- exports.hkdfHmacSha512 = hkdfHmacSha512;
640
755
  exports.hmacSha256 = hmacSha256;
641
756
  exports.hmacSha512 = hmacSha512;
642
757
  exports.memzero = memzero;
643
758
  exports.memzeroVecVecU8 = memzeroVecVecU8;
644
759
  exports.pbkdf2HmacSha256 = pbkdf2HmacSha256;
645
- exports.pbkdf2HmacSha512 = pbkdf2HmacSha512;
646
760
  exports.schnorrPublicKeyFromPrivateKey = schnorrPublicKeyFromPrivateKey;
647
761
  exports.schnorrSign = schnorrSign;
648
762
  exports.schnorrSignUsing = schnorrSignUsing;