@leofcoin/peernet 1.2.30 → 3.0.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.
Files changed (120) hide show
  1. package/README.md +13 -0
  2. package/docs/automatic-transport.md +37 -0
  3. package/exports/browser/{browser-DvU1xNFS.js → browser-CCfR9KOM.js} +1 -1
  4. package/exports/browser/{client-86Tnax66.js → client-C_pBoi1g.js} +254 -78
  5. package/exports/browser/{identity-CYVPDmkf.js → identity-Cf8KKnho.js} +511 -391
  6. package/exports/browser/identity.js +1 -1
  7. package/exports/browser/{index-BD0Anx7_.js → index-dTQVgkpf.js} +1 -1
  8. package/exports/browser/{messages-D7JxkkDW.js → messages-BGHaihSi.js} +2 -2
  9. package/exports/browser/{peernet-C4rOvyyU.js → peernet-Db43ag2D.js} +68 -45
  10. package/exports/browser/peernet.js +2 -2
  11. package/exports/store.js +0 -3
  12. package/package.json +10 -6
  13. package/.esdoc.json +0 -10
  14. package/.gitattributes +0 -2
  15. package/.github/workflows/release.yml +0 -34
  16. package/.prettierrc +0 -7
  17. package/.travis.yml +0 -27
  18. package/BREAKING_CHANGES.md +0 -35
  19. package/deploy.js +0 -8
  20. package/exports/browser/browser-D-r0O9Qn.js +0 -53
  21. package/exports/browser/browser-_hiyXwPp.js +0 -147
  22. package/exports/browser/client-BFxJts6j.js +0 -2224
  23. package/exports/browser/client-BVhUamQG.js +0 -2200
  24. package/exports/browser/client-BzvWzzLv.js +0 -2224
  25. package/exports/browser/client-C9GBz2Tf.js +0 -2224
  26. package/exports/browser/client-CQzuu6At.js +0 -2224
  27. package/exports/browser/client-CVkFejdx.js +0 -2224
  28. package/exports/browser/client-Cj_UUO8W.js +0 -2224
  29. package/exports/browser/client-CrGaeBjj.js +0 -2224
  30. package/exports/browser/client-DDC8C510.js +0 -2224
  31. package/exports/browser/client-ERocgKET.js +0 -2224
  32. package/exports/browser/client-a8rws3cu.js +0 -2224
  33. package/exports/browser/identity-ChyyZSve.js +0 -8397
  34. package/exports/browser/index-Bxr5Iztg.js +0 -37
  35. package/exports/browser/messages-BFCmg6Vb.js +0 -212
  36. package/exports/browser/messages-BHIC2mQu.js +0 -212
  37. package/exports/browser/messages-CimzJ4wr.js +0 -210
  38. package/exports/browser/messages-Cjoa_LGO.js +0 -210
  39. package/exports/browser/messages-DH0tgNM9.js +0 -207
  40. package/exports/browser/messages-DVHcNvs_.js +0 -212
  41. package/exports/browser/messages-DqL_g2qw.js +0 -210
  42. package/exports/browser/messages-UKnuelZ7.js +0 -207
  43. package/exports/browser/messages-XgZZUMma.js +0 -212
  44. package/exports/browser/messages-kfFyctPL.js +0 -210
  45. package/exports/browser/messages-psROnfRi.js +0 -212
  46. package/exports/browser/peernet-B9VL4Xwe.js +0 -9522
  47. package/exports/browser/peernet-C-HNdrcd.js +0 -9528
  48. package/exports/browser/peernet-Ca1iM2tN.js +0 -9336
  49. package/exports/browser/peernet-CbI0-jFn.js +0 -9651
  50. package/exports/browser/peernet-CtHScDyh.js +0 -9524
  51. package/exports/browser/peernet-DfuxUK3u.js +0 -9525
  52. package/exports/browser/peernet-DiEcNDLD.js +0 -9655
  53. package/exports/browser/peernet-DtuRXOzP.js +0 -9653
  54. package/exports/browser/peernet-r_9IyzTe.js +0 -9336
  55. package/exports/browser/peernet-rcD5XL1y.js +0 -9590
  56. package/exports/browser/peernet-rw8HJGOz.js +0 -9597
  57. package/exports/messages-CHKVVTVE.js +0 -204
  58. package/exports/messages-DaUtFfBh.js +0 -207
  59. package/index.html +0 -19
  60. package/rollup.config.js +0 -143
  61. package/src/dht/dht.ts +0 -142
  62. package/src/discovery/peer-discovery.js +0 -75
  63. package/src/errors/errors.js +0 -12
  64. package/src/file-transfer.ts +0 -194
  65. package/src/handlers/data.js +0 -15
  66. package/src/handlers/message.js +0 -34
  67. package/src/identity.ts +0 -172
  68. package/src/messages/chat.ts +0 -13
  69. package/src/messages/data-response.ts +0 -13
  70. package/src/messages/data.ts +0 -17
  71. package/src/messages/dht-response.ts +0 -13
  72. package/src/messages/dht.ts +0 -21
  73. package/src/messages/file-link.ts +0 -17
  74. package/src/messages/file.ts +0 -17
  75. package/src/messages/peer-response.ts +0 -13
  76. package/src/messages/peer.ts +0 -13
  77. package/src/messages/peernet.ts +0 -13
  78. package/src/messages/ps.ts +0 -13
  79. package/src/messages/request.ts +0 -13
  80. package/src/messages/response.ts +0 -13
  81. package/src/messages.js +0 -12
  82. package/src/peer-info.js +0 -9
  83. package/src/peernet.ts +0 -1113
  84. package/src/prompts/password/browser.js +0 -1
  85. package/src/prompts/password/node.js +0 -6
  86. package/src/prompts/password.js +0 -1
  87. package/src/proto/chat-message.proto.js +0 -6
  88. package/src/proto/data-response.proto.js +0 -4
  89. package/src/proto/data.proto.js +0 -4
  90. package/src/proto/dht-response.proto.js +0 -4
  91. package/src/proto/dht.proto.js +0 -4
  92. package/src/proto/file-link.proto.js +0 -5
  93. package/src/proto/file.proto.js +0 -10
  94. package/src/proto/peer-response.proto.js +0 -3
  95. package/src/proto/peer.proto.js +0 -3
  96. package/src/proto/peernet.proto.js +0 -7
  97. package/src/proto/ps.proto.js +0 -4
  98. package/src/proto/request.proto.js +0 -4
  99. package/src/proto/response.proto.js +0 -3
  100. package/src/types.ts +0 -25
  101. package/src/utils/utils.js +0 -77
  102. package/test/all.js +0 -5
  103. package/test/client.js +0 -15
  104. package/test/codec.js +0 -56
  105. package/test/file-transfer.test.js +0 -81
  106. package/test/fresh-empty-store.js +0 -15
  107. package/test/hash.js +0 -14
  108. package/test/index.js +0 -6
  109. package/test/lastBlock.js +0 -7
  110. package/test/messages.js +0 -26
  111. package/test/peer-data-exchange.test.js +0 -52
  112. package/test/peer-file-exchange.test.js +0 -78
  113. package/test/peernet.js +0 -17
  114. package/test/peernet.test.js +0 -440
  115. package/test-output.log +0 -84
  116. package/test.js +0 -63
  117. package/test2.js +0 -13
  118. package/test3.js +0 -16
  119. package/test4.js +0 -7
  120. package/tsconfig.json +0 -13
@@ -344,13 +344,13 @@ const ALPHABET$1 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
344
344
  const ALPHABET_HEX$1 = "0123456789ABCDEFGHJKLMNPQRSTUVabcdefghijklmnopqrstuv";
345
345
  const base58 = base(ALPHABET$1);
346
346
  const base58Hex = base(ALPHABET_HEX$1);
347
- const encode$4 = base58.encode;
348
- const decode$5 = base58.decode;
347
+ const encode$3 = base58.encode;
348
+ const decode$4 = base58.decode;
349
349
  const encodeHex$2 = base58Hex.encode;
350
350
  const decodeHex$2 = base58Hex.decode;
351
351
  const isBase58 = (string) => {
352
352
  try {
353
- decode$5(string);
353
+ decode$4(string);
354
354
  return true;
355
355
  }
356
356
  catch (e) {
@@ -368,7 +368,7 @@ const isBase58Hex = (string) => {
368
368
  };
369
369
  const whatType = (string) => {
370
370
  try {
371
- decode$5(string);
371
+ decode$4(string);
372
372
  return "base58";
373
373
  }
374
374
  catch (e) {
@@ -382,8 +382,8 @@ const whatType = (string) => {
382
382
  }
383
383
  };
384
384
  var base58$1 = {
385
- encode: encode$4,
386
- decode: decode$5,
385
+ encode: encode$3,
386
+ decode: decode$4,
387
387
  isBase58,
388
388
  isBase58Hex,
389
389
  encodeHex: encodeHex$2,
@@ -470,7 +470,7 @@ const concatAndDoubleHash = async (input) => {
470
470
  return new Uint8Array(await createDoubleHash(typedArrayConcat(input), 'SHA-256'));
471
471
  };
472
472
 
473
- const encode$3 = async (source, prefix = new TextEncoder().encode('00'), hex) => {
473
+ const encode$2 = async (source, prefix = new TextEncoder().encode('00'), hex) => {
474
474
  if (!(source instanceof Uint8Array) || !(prefix instanceof Uint8Array)) {
475
475
  throw new TypeError('Expected Uint8Array');
476
476
  }
@@ -487,7 +487,7 @@ const encode$3 = async (source, prefix = new TextEncoder().encode('00'), hex) =>
487
487
  return base58$1.encodeHex(uint8Array);
488
488
  return base58$1.encode(uint8Array);
489
489
  };
490
- const decode$4 = async (string, hex) => {
490
+ const decode$3 = async (string, hex) => {
491
491
  let uint8Array = hex ? base58$1.decodeHex(string) : base58$1.decode(string);
492
492
  const prefix = uint8Array.subarray(0, 2);
493
493
  const source = uint8Array.subarray(2, -4);
@@ -507,129 +507,242 @@ const decode$4 = async (string, hex) => {
507
507
  };
508
508
  const isBase58check = (string, hex) => {
509
509
  try {
510
- hex ? decode$4(string, true) : decode$4(string);
510
+ hex ? decode$3(string, true) : decode$3(string);
511
511
  return true;
512
512
  }
513
513
  catch (e) {
514
514
  return false;
515
515
  }
516
516
  };
517
- const encodeHex$1 = (uint8Array, prefix = new TextEncoder().encode('00')) => encode$3(uint8Array, prefix, true);
518
- const decodeHex$1 = (string) => decode$4(string, true);
517
+ const encodeHex$1 = (uint8Array, prefix = new TextEncoder().encode('00')) => encode$2(uint8Array, prefix, true);
518
+ const decodeHex$1 = (string) => decode$3(string, true);
519
519
  const isBase58checkHex = (string) => isBase58check(string, true);
520
- var base58check = { encode: encode$3, decode: decode$4, encodeHex: encodeHex$1, decodeHex: decodeHex$1, isBase58check, isBase58checkHex };
521
-
522
- const MSB$1 = 0x80;
523
- const MSBALL = -128;
524
- const INT = Math.pow(2, 31);
525
- const encode$2 = (num, out, offset) => {
526
- if (Number.MAX_SAFE_INTEGER && num > Number.MAX_SAFE_INTEGER) {
527
- encode$2.bytes = 0;
528
- throw new RangeError('Could not encode varint');
529
- }
530
- out = out || [];
531
- offset = offset || 0;
532
- const oldOffset = offset;
533
- while (num >= INT) {
534
- out[offset++] = (num & 0xFF) | MSB$1;
535
- num /= 128;
536
- }
537
- while (num & MSBALL) {
538
- out[offset++] = (num & 0xFF) | MSB$1;
539
- num >>>= 7;
540
- }
541
- out[offset] = num | 0;
542
- encode$2.bytes = offset - oldOffset + 1;
543
- return out;
544
- };
520
+ var base58check = { encode: encode$2, decode: decode$3, encodeHex: encodeHex$1, decodeHex: decodeHex$1, isBase58check, isBase58checkHex };
545
521
 
546
- const MSB = 0x80;
547
- const REST = 0x7F;
548
- const decode$3 = (buf, offset) => {
549
- offset = offset || 0;
550
- const l = buf.length;
551
- let counter = offset;
552
- let result = 0;
553
- let shift = 0;
554
- let b;
555
- do {
556
- if (counter >= l || shift > 49) {
557
- decode$3.bytes = 0;
558
- throw new RangeError('Could not decode varint');
522
+ /** @leofcoin/binary: dependency-free unsigned framing, with no global byte counters. */
523
+ const MAX_BIGINT = (1n << 256n) - 1n;
524
+ function size(value) {
525
+ if (!Number.isSafeInteger(value) || value < 0)
526
+ throw new RangeError('Expected an unsigned safe integer');
527
+ }
528
+ function bytes(value) {
529
+ if (!(value instanceof Uint8Array))
530
+ throw new TypeError('Expected Uint8Array');
531
+ }
532
+ function varUintLength(value) {
533
+ size(value);
534
+ let length = 1;
535
+ while (value >= 128) {
536
+ value = Math.floor(value / 128);
537
+ length++;
538
+ }
539
+ return length;
540
+ }
541
+ function varBigIntLength(value) {
542
+ if (typeof value !== 'bigint')
543
+ throw new TypeError('Expected BigInt');
544
+ if (value < 0n || value > MAX_BIGINT)
545
+ throw new RangeError('Expected an unsigned 256-bit integer');
546
+ let length = 1;
547
+ while (value >= 128n) {
548
+ value >>= 7n;
549
+ length++;
550
+ }
551
+ return length;
552
+ }
553
+ /** Fixed-capacity writer. finish() is a view; copy it before reusing/resetting the writer. */
554
+ class BinaryWriter {
555
+ #buffer;
556
+ #position = 0;
557
+ constructor(capacity = 64) {
558
+ if (typeof capacity === 'number') {
559
+ size(capacity);
560
+ this.#buffer = new Uint8Array(capacity);
559
561
  }
560
- b = buf[counter++];
561
- result += shift < 28
562
- ? (b & REST) << shift
563
- : (b & REST) * Math.pow(2, shift);
564
- shift += 7;
565
- } while (b >= MSB);
566
- decode$3.bytes = counter - offset;
567
- return result;
568
- };
569
-
570
- const N1 = Math.pow(2, 7);
571
- const N2 = Math.pow(2, 14);
572
- const N3 = Math.pow(2, 21);
573
- const N4 = Math.pow(2, 28);
574
- const N5 = Math.pow(2, 35);
575
- const N6 = Math.pow(2, 42);
576
- const N7 = Math.pow(2, 49);
577
- const N8 = Math.pow(2, 56);
578
- const N9 = Math.pow(2, 63);
579
- var encodingLength = (value) => (value < N1 ? 1
580
- : value < N2 ? 2
581
- : value < N3 ? 3
582
- : value < N4 ? 4
583
- : value < N5 ? 5
584
- : value < N6 ? 6
585
- : value < N7 ? 7
586
- : value < N8 ? 8
587
- : value < N9 ? 9
588
- : 10);
589
-
590
- var index$4 = {
591
- encode: encode$2,
592
- decode: decode$3,
593
- encodingLength
594
- };
562
+ else {
563
+ bytes(capacity);
564
+ this.#buffer = capacity;
565
+ }
566
+ }
567
+ get position() {
568
+ return this.#position;
569
+ }
570
+ get remaining() {
571
+ return this.#buffer.length - this.#position;
572
+ }
573
+ #require(length) {
574
+ size(length);
575
+ if (length > this.remaining)
576
+ throw new RangeError('Binary output buffer is too small');
577
+ }
578
+ writeVarUint(value) {
579
+ this.#require(varUintLength(value));
580
+ this.#writeVarUint(value);
581
+ return this;
582
+ }
583
+ #writeVarUint(value) {
584
+ while (value >= 128) {
585
+ this.#buffer[this.#position++] = value % 128 | 128;
586
+ value = Math.floor(value / 128);
587
+ }
588
+ this.#buffer[this.#position++] = value;
589
+ }
590
+ writeVarBigInt(value) {
591
+ this.#require(varBigIntLength(value));
592
+ do {
593
+ const byte = Number(value & 127n);
594
+ value >>= 7n;
595
+ this.#buffer[this.#position++] = byte | (value ? 128 : 0);
596
+ } while (value);
597
+ return this;
598
+ }
599
+ writeBytes(value) {
600
+ bytes(value);
601
+ this.#require(value.length);
602
+ this.#buffer.set(value, this.#position);
603
+ this.#position += value.length;
604
+ return this;
605
+ }
606
+ writeFrame(value) {
607
+ bytes(value);
608
+ // Check the complete operation before writing its length prefix.
609
+ const prefixLength = varUintLength(value.length);
610
+ this.#require(prefixLength + value.length);
611
+ const prefixStart = this.#buffer.byteOffset + this.#position;
612
+ if (value.buffer === this.#buffer.buffer &&
613
+ value.byteOffset < prefixStart + prefixLength &&
614
+ value.byteOffset + value.length > prefixStart)
615
+ throw new RangeError('Frame source overlaps its length prefix');
616
+ this.#writeVarUint(value.length);
617
+ this.#buffer.set(value, this.#position);
618
+ this.#position += value.length;
619
+ return this;
620
+ }
621
+ reset() {
622
+ this.#position = 0;
623
+ return this;
624
+ }
625
+ finish(copy = false) {
626
+ const result = this.#buffer.subarray(0, this.#position);
627
+ // Buffer.slice() aliases memory; this constructor copies every Uint8Array subtype.
628
+ return copy ? new Uint8Array(result) : result;
629
+ }
630
+ }
631
+ /** Reads views of the original buffer. Failed operations leave the cursor unchanged. */
632
+ class BinaryReader {
633
+ #buffer;
634
+ #position = 0;
635
+ constructor(buffer) {
636
+ bytes(buffer);
637
+ this.#buffer = buffer;
638
+ }
639
+ get position() {
640
+ return this.#position;
641
+ }
642
+ get remaining() {
643
+ return this.#buffer.length - this.#position;
644
+ }
645
+ readVarUint(canonical = true) {
646
+ let result = 0;
647
+ let multiplier = 1;
648
+ for (let index = 0; index < 8; index++) {
649
+ const cursor = this.#position + index;
650
+ if (cursor >= this.#buffer.length)
651
+ throw new RangeError('Truncated varint');
652
+ const byte = this.#buffer[cursor];
653
+ const payload = byte & 127;
654
+ if (index === 7 && payload > Math.floor((Number.MAX_SAFE_INTEGER - result) / multiplier))
655
+ throw new RangeError('Varint exceeds safe integer range');
656
+ result += payload * multiplier;
657
+ if (byte < 128) {
658
+ if (canonical && index > 0 && payload === 0)
659
+ throw new RangeError('Non-canonical varint');
660
+ this.#position = cursor + 1;
661
+ return result;
662
+ }
663
+ multiplier *= 128;
664
+ }
665
+ throw new RangeError('Varint exceeds safe integer range');
666
+ }
667
+ readVarBigInt(canonical = true) {
668
+ let result = 0n;
669
+ for (let index = 0; index < 37; index++) {
670
+ const cursor = this.#position + index;
671
+ if (cursor >= this.#buffer.length)
672
+ throw new RangeError('Truncated varint');
673
+ const byte = this.#buffer[cursor];
674
+ result |= BigInt(byte & 127) << BigInt(index * 7);
675
+ if (result > MAX_BIGINT)
676
+ throw new RangeError('Varint exceeds 256 bits');
677
+ if (byte < 128) {
678
+ if (canonical && index > 0 && byte === 0)
679
+ throw new RangeError('Non-canonical varint');
680
+ this.#position = cursor + 1;
681
+ return result;
682
+ }
683
+ }
684
+ throw new RangeError('Varint exceeds 256 bits');
685
+ }
686
+ readBytes(length) {
687
+ size(length);
688
+ if (length > this.remaining)
689
+ throw new RangeError('Truncated binary field');
690
+ const start = this.#position;
691
+ this.#position += length;
692
+ return this.#buffer.subarray(start, this.#position);
693
+ }
694
+ readFrame(canonical = true) {
695
+ const start = this.#position;
696
+ try {
697
+ return this.readBytes(this.readVarUint(canonical));
698
+ }
699
+ catch (error) {
700
+ this.#position = start;
701
+ throw error;
702
+ }
703
+ }
704
+ }
705
+ /** Existing smart-concat bytes, with exactly one output allocation and no prefix arrays. */
706
+ function encodeFrames(frames, prefix) {
707
+ if (!Array.isArray(frames))
708
+ throw new TypeError('Expected an array of byte frames');
709
+ let length = 0;
710
+ for (const frame of frames) {
711
+ bytes(frame);
712
+ length += varUintLength(frame.length) + frame.length;
713
+ size(length);
714
+ }
715
+ const writer = new BinaryWriter(length);
716
+ for (const frame of frames)
717
+ writer.writeFrame(frame);
718
+ return writer.finish();
719
+ }
720
+ /** Iterative framing: bounded by the input length, not recursive stack depth. */
721
+ function decodeFrames(buffer, prefixLength = 0, options = {}) {
722
+ const reader = new BinaryReader(buffer);
723
+ reader.readBytes(prefixLength);
724
+ const maxFrames = options.maxFrames ?? buffer.length;
725
+ size(maxFrames);
726
+ const frames = [];
727
+ while (reader.remaining) {
728
+ if (frames.length >= maxFrames)
729
+ throw new RangeError('Too many binary frames');
730
+ frames.push(reader.readFrame(options.canonical ?? true));
731
+ }
732
+ return frames;
733
+ }
595
734
 
596
- var index$3 = (input, prefix) => {
597
- const encodedArray = [];
598
- const length = input.reduce((total, current) => {
599
- const encoded = index$4.encode(current.length);
600
- encodedArray.push(encoded);
601
- total += current.length + encoded.length;
602
- return total;
603
- }, 0);
604
- const typedArray = new Uint8Array(length);
605
- let currentIndex = 0;
606
- let index = 0;
607
- for (const source of input) {
608
- typedArray.set(encodedArray[index], currentIndex);
609
- currentIndex += encodedArray[index].length;
610
- typedArray.set(source, currentIndex);
611
- currentIndex += source.length;
612
- index += 1;
613
- }
614
- return typedArray;
735
+ const asBytes = (source) => {
736
+ if (source instanceof Uint8Array)
737
+ return source;
738
+ // Keep legacy ArrayLike coercion. Typed-array callers take the zero-copy path.
739
+ const bytes = new Uint8Array(source.length);
740
+ bytes.set(source);
741
+ return bytes;
615
742
  };
743
+ var index$3 = (input, prefix) => encodeFrames(input.map(asBytes));
616
744
 
617
- var index$2 = (typedArray, prefix) => {
618
- const set = [];
619
- const varintAndSub = (typedArray) => {
620
- const length = index$4.decode(typedArray);
621
- // remove length
622
- typedArray = typedArray.subarray(index$4.decode.bytes);
623
- // push value
624
- set.push(typedArray.subarray(0, length));
625
- // remove value
626
- typedArray = typedArray.subarray(length);
627
- if (typedArray.length !== 0)
628
- return varintAndSub(typedArray);
629
- return set;
630
- };
631
- return varintAndSub(typedArray);
632
- };
745
+ var index$2 = (typedArray, prefix) => decodeFrames(typedArray, 0, { canonical: false });
633
746
 
634
747
  const decode$2 = (multiWif, expectedVersion, expectedCodec) => {
635
748
  const decoded = base58$1.decode(multiWif);
@@ -687,176 +800,190 @@ var index$1 = {
687
800
  * * b = `7n` // equation param
688
801
  * * Gx, Gy are coordinates of Generator / base point
689
802
  */
803
+ const freeze = Object.freeze;
804
+ const P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn;
805
+ const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
806
+ const Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n;
807
+ const Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n;
690
808
  // Mirror noble-curves: Point.CURVE() returns shared params, but those params must stay frozen so
691
809
  // callers cannot mutate them out from under the arithmetic constants captured below.
692
- const secp256k1_CURVE = Object.freeze({
693
- p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
694
- n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
810
+ const secp256k1_CURVE = freeze({
811
+ p: P,
812
+ n: N,
695
813
  h: 1n,
696
814
  a: 0n,
697
815
  b: 7n,
698
- Gx: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,
699
- Gy: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n,
816
+ Gx,
817
+ Gy,
700
818
  });
701
- const { p: P, n: N, Gx, Gy, b: _b } = secp256k1_CURVE;
702
819
  // 32-byte field / scalar width, and the SHA-256 / HMAC-DRBG output width used
703
820
  // by the RFC6979 paths here.
704
821
  const L = 32;
705
- const L2 = 64; // 64-byte compact signatures, and 64 hex chars for zero-padded 32-byte scalars
706
- const lengths = {
707
- publicKey: L + 1,
708
- publicKeyUncompressed: L2 + 1,
709
- // 48-byte keygen seed floor: 384 bits exceeds FIPS 186-5 Table A.2's
710
- // 352-bit recommendation for 256-bit prime curves.
711
- seed: L + L / 2,
712
- };
713
822
  // Helpers and Precomputes sections are reused between libraries
714
823
  // ## Helpers
715
824
  // ----------
716
- const err = (message = '', E = Error) => {
717
- const e = new E(message);
718
- const { captureStackTrace } = Error;
719
- if (typeof captureStackTrace === 'function')
720
- captureStackTrace(e, err);
721
- throw e;
825
+ /** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
826
+ const isBytes = (a) => {
827
+ // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.
828
+ // The fallback still requires a real ArrayBuffer view, so plain
829
+ // JSON-deserialized `{ constructor: ... }` spoofing is rejected, and
830
+ // `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
831
+ return (a instanceof Uint8Array ||
832
+ (ArrayBuffer.isView(a) &&
833
+ a.constructor.name === 'Uint8Array' &&
834
+ a.BYTES_PER_ELEMENT === 1));
722
835
  };
723
- // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. The
724
- // fallback still requires a real ArrayBuffer view so plain JSON-deserialized `{ constructor: ... }`
725
- // spoofing is rejected, and `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
726
- const isBytes = (a) => a instanceof Uint8Array ||
727
- (ArrayBuffer.isView(a) &&
728
- a.constructor.name === 'Uint8Array' &&
729
- a.BYTES_PER_ELEMENT === 1);
730
- /** Asserts something is Bytes. */
836
+ /** Asserts something is Uint8Array. */
731
837
  const abytes = (value, length, title = '') => {
838
+ // Success path first: this runs at the start of every update() / digestInto(), and the
839
+ // common `abytes(data)` form must not pay for length handling it does not use.
840
+ if (isBytes(value) && (length === undefined || value.length === length))
841
+ return value;
842
+ // Error path: recompute freely to build the exact message.
732
843
  const bytes = isBytes(value);
733
- const len = value?.length;
734
- const needsLen = length !== undefined;
735
- if (!bytes || (needsLen && len !== length)) {
736
- const prefix = title && `"${title}" `;
737
- const ofLen = needsLen ? ` of length ${length}` : '';
738
- const got = bytes ? `length=${len}` : `type=${typeof value}`;
739
- const msg = prefix + 'expected Uint8Array' + ofLen + ', got ' + got;
740
- return bytes ? err(msg, RangeError) : err(msg, TypeError);
741
- }
742
- return value;
844
+ const ofLen = length !== undefined ? ` of length ${length}` : '';
845
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
846
+ const message = (title ? `"${title}" ` : '') + 'expected Uint8Array' + ofLen + ', got ' + got;
847
+ if (!bytes)
848
+ throw new TypeError(message);
849
+ throw new RangeError(message);
743
850
  };
744
- /** create Uint8Array */
745
- const u8n = (len) => new Uint8Array(len);
851
+ // Signing can retain the message across hash callbacks / awaits, and Schnorr hashes it more than
852
+ // once. Take one owned snapshot so caller mutation cannot change the signing transcript.
853
+ // cloneBytes expects an already-validated view; snapshotBytes validates, then copies.
854
+ const cloneBytes = (value) => Uint8Array.from(value);
855
+ const snapshotBytes = (value, title, length) => cloneBytes(abytes(value, length, title));
746
856
  // Callers keep values non-negative and within the requested width; padStart() won't truncate over-wide inputs.
747
857
  const padh = (n, pad) => n.toString(16).padStart(pad, '0');
748
- /** Render bytes as lowercase hex. */
749
- const bytesToHex = (b) => {
858
+ /** Convert byte array to hex string. */
859
+ const bytesToHex = (bytes) => {
750
860
  let hex = '';
751
- for (const e of abytes(b))
752
- hex += padh(e, 2);
861
+ for (const byte of abytes(bytes))
862
+ hex += padh(byte, 2);
753
863
  return hex;
754
864
  };
755
- const C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters
756
- // Strict ASCII nibble parser: non-ASCII hex lookalikes are rejected as undefined.
757
- // prettier-ignore
758
- const _ch = (ch) => ch >= C._0 && ch <= C._9 ? ch - C._0 // '2' => 50-48
759
- : ch >= C.A && ch <= C.F ? ch - (C.A - 10) // 'B' => 66-(65-10)
760
- : ch >= C.a && ch <= C.f ? ch - (C.a - 10) // 'b' => 98-(97-10)
761
- : undefined;
865
+ /** Convert hex string to byte array. */
762
866
  const hexToBytes = (hex) => {
763
- const e = 'hex invalid'; // Strict ASCII hex only, with one generic error for type and parse failures.
867
+ const e = 'hex invalid'; // Strict ASCII hex only, with one generic error for parse failures.
764
868
  if (typeof hex !== 'string')
765
- return err(e);
766
- const hl = hex.length;
767
- const al = hl / 2;
768
- if (hl % 2)
769
- return err(e);
770
- const array = u8n(al);
771
- for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
772
- // treat each char as ASCII
773
- const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16
774
- const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char
775
- if (n1 === undefined || n2 === undefined)
776
- return err(e);
777
- array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9
869
+ throw new TypeError(e);
870
+ if (hex.length % 2 || !/^[\da-f]*$/i.test(hex))
871
+ throw new RangeError(e);
872
+ const array = new Uint8Array(hex.length / 2);
873
+ for (let ai = 0, hi = 0; ai < array.length; ai++, hi += 2) {
874
+ const n1 = hex.charCodeAt(hi);
875
+ const n2 = hex.charCodeAt(hi + 1);
876
+ // Regex guarantees ASCII. For 0..9/A..F/a..f, this maps char codes to 0..15.
877
+ array[ai] = ((n1 & 15) + (n1 >> 6) * 9) * 16 + (n2 & 15) + (n2 >> 6) * 9;
778
878
  }
779
879
  return array;
780
880
  };
781
881
  // WebCrypto is available in all modern environments
782
- const subtle = () => globalThis?.crypto?.subtle ?? err('crypto.subtle must be defined, consider polyfill');
783
- // prettier-ignore
784
- const concatBytes = (...arrs) => {
785
- let len = 0;
786
- for (const a of arrs)
787
- len += abytes(a).length; // validate every input and sum lengths before copying
788
- const r = u8n(len);
789
- let pad = 0; // walk through each array,
790
- for (const a of arrs)
791
- r.set(a, pad), pad += a.length; // ensure they have proper type
792
- return r;
882
+ const subtle = () => {
883
+ const s = globalThis?.crypto?.subtle;
884
+ if (s)
885
+ return s;
886
+ throw new Error('crypto.subtle must be defined, consider polyfill');
887
+ };
888
+ /** Copies several Uint8Arrays into one. */
889
+ const concatBytes = (...arrays) => {
890
+ let sum = 0;
891
+ for (const a of arrays)
892
+ sum += abytes(a).length;
893
+ const res = new Uint8Array(sum);
894
+ let pad = 0;
895
+ for (const a of arrays) {
896
+ res.set(a, pad);
897
+ pad += a.length;
898
+ }
899
+ return res;
793
900
  };
794
901
  /**
795
902
  * WebCrypto OS-level CSPRNG (random number generator).
796
903
  * Will throw when not available; large-request ceilings are delegated to getRandomValues().
797
904
  */
798
- const randomBytes = (len = L) => (globalThis?.crypto).getRandomValues(u8n(len));
905
+ const randomBytes = (len = L) => {
906
+ const c = globalThis?.crypto;
907
+ if (typeof c?.getRandomValues !== 'function')
908
+ throw new Error('crypto.getRandomValues must be defined, consider polyfill');
909
+ return c.getRandomValues(new Uint8Array(len));
910
+ };
799
911
  const big = BigInt;
800
912
  const arange = (n, min, max, msg = 'bad number: out of range') => {
801
913
  if (typeof n !== 'bigint')
802
- return err(msg, TypeError);
914
+ throw new TypeError(msg);
803
915
  if (min <= n && n < max)
804
916
  return n;
805
- return err(msg, RangeError);
917
+ throw new RangeError(msg);
806
918
  };
807
919
  /** Canonical modular reduction. Callers must provide a positive modulus. */
808
- const M = (a, b = P) => {
809
- const r = a % b;
810
- return r >= 0n ? r : b + r;
811
- };
920
+ const M = (a, b = P) => ((a %= b) >= 0n ? a : b + a);
812
921
  const modN = (a) => M(a, N);
813
- /** Modular inversion using eucledian GCD (non-CT). No negative exponent for now. */
814
- // prettier-ignore
815
- const invert = (num, md) => {
816
- if (num === 0n || md <= 0n)
817
- err('no inverse n=' + num + ' mod=' + md);
818
- let a = M(num, md), b = md, x = 0n, u = 1n;
922
+ /** Modular inversion using extended euclidean GCD. Variable-time (non-CT). */
923
+ const invert = (number, modulo) => {
924
+ if (number === 0n)
925
+ throw new Error('invert: expected non-zero number');
926
+ // modulo = 1 is the zero ring: gcd(x, 1) = 1 makes the loop below "succeed" and return the
927
+ // useless inverse 0. Reject it.
928
+ if (modulo <= 1n)
929
+ throw new Error('invert: expected modulus > 1, got ' + modulo);
930
+ // This is variable-time: the loop count depends on `number`.
931
+ let a = M(number, modulo);
932
+ let b = modulo;
933
+ // Only the Bézout coefficient of `number` (x/u chain) is tracked; the coefficient of `modulo`
934
+ // never affects the output, so it is not computed.
935
+ // prettier-ignore
936
+ let x = 0n, u = 1n;
819
937
  while (a !== 0n) {
820
- const q = b / a, r = b % a;
938
+ const q = b / a;
939
+ const r = b - a * q;
821
940
  const m = x - u * q;
941
+ // prettier-ignore
822
942
  b = a, a = r, x = u, u = m;
823
943
  }
824
- return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point
944
+ const gcd = b;
945
+ if (gcd !== 1n)
946
+ throw new Error('invert: does not exist');
947
+ return M(x, modulo);
825
948
  };
826
- const callHash = (name) => {
949
+ const _hash = (name) => {
827
950
  // @ts-ignore
828
951
  const fn = hashes[name];
829
952
  if (typeof fn !== 'function')
830
- err('hashes.' + name + ' not set');
953
+ throw new Error('hashes.' + name + ' not set');
831
954
  return fn;
832
955
  };
833
956
  // All exported provider slots are caller-configurable and may be unset or return arbitrary values,
834
957
  // so wrapper helpers must enforce the exact 32-byte digest contract instead of trusting providers.
835
- const gh = (name, a, b) => abytes(callHash(name)(a, b), L, 'digest');
836
- const gha = (name, a, b) => Promise.resolve(callHash(name)(a, b)).then((r) => abytes(r, L, 'digest'));
958
+ const callHash = (name, a, b) => abytes(_hash(name)(a, b), L, 'digest');
959
+ const callHashAsync = async (name, a, b) => abytes(await _hash(name)(a, b), L, 'digest');
837
960
  // also rejects structurally similar Point values from other realms / bundled copies
838
- const apoint = (p) => (p instanceof Point ? p : err('Point expected'));
961
+ const apoint = (p) => {
962
+ if (p instanceof Point)
963
+ return p;
964
+ throw new TypeError('Point expected');
965
+ };
839
966
  // ## End of Helpers
840
967
  // -----------------
968
+ const E_BADPOINT = 'bad point: not on curve';
841
969
  /**
842
970
  * secp256k1 formula. Koblitz curves are subclass of weierstrass curves with a=0,
843
971
  * making it x³+b; callers validate x first.
844
972
  */
845
- const koblitz = (x) => M(M(x * x) * x + _b);
973
+ const koblitz = (x) => M(M(x * x) * x + 7n);
846
974
  /** assert is element of field mod P (incl. 0 for projective infinity coordinates) */
847
975
  const FpIsValid = (n) => arange(n, 0n, P);
848
976
  /** assert is element of field mod P (excl. 0 where current callers need a non-zero coordinate) */
849
977
  const FpIsValidNot0 = (n) => arange(n, 1n, P);
850
- /** assert is element of field mod N (excl. 0), matching the shared BIP340 scalar-failure rule used here */
978
+ /** assert is element of field mod N (excl. 0), matching the shared BIP340 scalar-failure rule used here.
979
+ * There is deliberately no FnIsValid: no caller accepts the scalar 0. */
851
980
  const FnIsValidNot0 = (n) => arange(n, 1n, N);
852
981
  // Shared parity primitive for BIP340 even-y checks and SEC 1 compressed prefixes.
853
982
  const isEven = (y) => !(y & 1n);
854
- /** create Uint8Array of byte n */
855
- const u8of = (n) => Uint8Array.of(n);
856
983
  /** SEC 1 compressed-prefix helper. Parity only: callers validate y before asking for the prefix byte. */
857
- const getPrefix = (y) => u8of(isEven(y) ? 0x02 : 0x03);
858
- /** lift_x from BIP340 returns the unique even square root for x³+7.
859
- * SEC 1 callers still flip it for the odd-prefix branch. */
984
+ const getPrefix = (y) => Uint8Array.of(isEven(y) ? 0x02 : 0x03);
985
+ /** lift_x from BIP340 returns the unique point with x and an even square root of x³+7.
986
+ * SEC 1 callers still negate it for the odd-prefix branch. */
860
987
  const lift_x = (x) => {
861
988
  // Let c = x³ + 7 mod p. Fail if x ≥ p. (also fail if x < 1)
862
989
  const c = koblitz(FpIsValidNot0(x));
@@ -872,8 +999,8 @@ const lift_x = (x) => {
872
999
  num = (num * num) % P; // Not constant-time.
873
1000
  }
874
1001
  if (M(r * r) !== c)
875
- err('sqrt invalid'); // check if result is valid
876
- return isEven(r) ? r : M(-r);
1002
+ throw new Error('sqrt invalid'); // check if result is valid
1003
+ return new Point(x, isEven(r) ? r : M(-r), 1n);
877
1004
  };
878
1005
  /**
879
1006
  * Point in 3d xyz projective coordinates. 3d takes less inversions than 2d.
@@ -897,7 +1024,7 @@ class Point {
897
1024
  this.X = FpIsValid(X);
898
1025
  this.Y = FpIsValidNot0(Y); // Y can't be 0 in Projective
899
1026
  this.Z = FpIsValid(Z);
900
- Object.freeze(this);
1027
+ freeze(this);
901
1028
  }
902
1029
  /** Returns the shared curve metadata object by reference.
903
1030
  * It is readonly only at type level, and mutating it won't retarget arithmetic,
@@ -913,30 +1040,31 @@ class Point {
913
1040
  /** Convert Uint8Array or hex string to Point. */
914
1041
  static fromBytes(bytes) {
915
1042
  abytes(bytes);
916
- const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; // e.g. for 32-byte: 33, 65
917
- let p = undefined;
918
1043
  const length = bytes.length;
919
1044
  const head = bytes[0];
920
- const tail = bytes.subarray(1);
921
- const x = sliceBytesNumBE(tail, 0, L);
1045
+ const x = sliceBytesNumBE(bytes, 1, 33);
922
1046
  // SEC 1 defines the rare infinity encoding 0x00, but SEC 1 public-key validation rejects
923
1047
  // infinity. We keep 0x00 rejected here because this parser is reused by verify(), ECDH,
924
1048
  // and public-key validation helpers, so strict handling applies to all callers by default.
925
1049
  // Local secp256k1 crosstests show OpenSSL raw point codecs accept 0x00 too.
926
- // Parse SEC 1 compressed/uncompressed encodings, then finish with assertValidity() before returning.
927
- if (length === comp && (head === 0x02 || head === 0x03)) {
928
- // Equation is y² == x³ + ax + b. We calculate y from x.
929
- // lift_x() returns the even root; SEC 1 0x03 still needs the odd root.
930
- let y = lift_x(x);
931
- if (head === 0x03)
932
- y = M(-y);
933
- p = new Point(x, y, 1n);
1050
+ // Parse and validate SEC 1 compressed/uncompressed encodings before returning.
1051
+ try {
1052
+ if (length === 33 && (head === 0x02 || head === 0x03)) {
1053
+ // Equation is y² == x³ + ax + b. We calculate y from x.
1054
+ // lift_x() returns the even point; SEC 1 0x03 still needs the odd point.
1055
+ const p = lift_x(x);
1056
+ return head === 0x03 ? p.negate() : p;
1057
+ }
1058
+ // Uncompressed 65-byte point, 0x04 prefix
1059
+ if (length === 65 && head === 0x04)
1060
+ return new Point(x, sliceBytesNumBE(bytes, 33, 65), 1n).assertValidity();
934
1061
  }
935
- // Uncompressed 65-byte point, 0x04 prefix
936
- if (length === uncomp && head === 0x04)
937
- p = new Point(x, sliceBytesNumBE(tail, L, L2), 1n);
938
- // Validate point
939
- return p ? p.assertValidity() : err('bad point: not on curve');
1062
+ catch (error) {
1063
+ // Out-of-range coordinates and non-residue x report the same error as wrong
1064
+ // prefixes / off-curve points, instead of generic range-check messages.
1065
+ throw new Error(E_BADPOINT);
1066
+ }
1067
+ throw new Error(E_BADPOINT);
940
1068
  }
941
1069
  static fromHex(hex) {
942
1070
  return Point.fromBytes(hexToBytes(hex));
@@ -951,14 +1079,10 @@ class Point {
951
1079
  equals(other) {
952
1080
  const { X: X1, Y: Y1, Z: Z1 } = this;
953
1081
  const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality
954
- const X1Z2 = M(X1 * Z2);
955
- const X2Z1 = M(X2 * Z1);
956
- const Y1Z2 = M(Y1 * Z2);
957
- const Y2Z1 = M(Y2 * Z1);
958
- return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
1082
+ return M(X1 * Z2) === M(X2 * Z1) && M(Y1 * Z2) === M(Y2 * Z1);
959
1083
  }
960
1084
  is0() {
961
- return this.equals(I);
1085
+ return this.Z === 0n;
962
1086
  }
963
1087
  /** Flip point over y coordinate. */
964
1088
  negate() {
@@ -978,7 +1102,7 @@ class Point {
978
1102
  const { X: X1, Y: Y1, Z: Z1 } = this;
979
1103
  const { X: X2, Y: Y2, Z: Z2 } = apoint(other);
980
1104
  const a = 0n;
981
- const b = _b;
1105
+ const b = 7n;
982
1106
  let X3 = 0n, Y3 = 0n, Z3 = 0n;
983
1107
  const b3 = M(b * 3n);
984
1108
  let t0 = M(X1 * X2), t1 = M(Y1 * Y2), t2 = M(Z1 * Z2), t3 = M(X1 + Y1); // step 1
@@ -1042,13 +1166,18 @@ class Point {
1042
1166
  // init result point & fake point
1043
1167
  let p = I;
1044
1168
  let f = G;
1045
- for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
1169
+ let d = this;
1170
+ // Safe mode always runs 256 iterations so ladder length can't leak the scalar's
1171
+ // leading zero bits; unsafe mode stops at the top set bit for speed.
1172
+ for (let i = 0; safe ? i < 256 : n > 0n; i++) {
1046
1173
  // if bit is present, add to point
1047
1174
  // if not present, add to fake, for timing safety
1048
1175
  if (n & 1n)
1049
1176
  p = p.add(d);
1050
1177
  else if (safe)
1051
1178
  f = f.add(d);
1179
+ d = d.double();
1180
+ n >>= 1n;
1052
1181
  }
1053
1182
  return p;
1054
1183
  }
@@ -1059,14 +1188,14 @@ class Point {
1059
1188
  toAffine() {
1060
1189
  const { X: x, Y: y, Z: z } = this;
1061
1190
  // fast-paths for ZERO point OR Z=1
1062
- if (this.equals(I))
1191
+ if (z === 0n)
1063
1192
  return { x: 0n, y: 0n };
1064
1193
  if (z === 1n)
1065
1194
  return { x, y };
1066
1195
  const iz = invert(z, P);
1067
1196
  // (Z * Z^-1) must be 1, otherwise bad math
1068
1197
  if (M(z * iz) !== 1n)
1069
- err('inverse invalid');
1198
+ throw new Error('inverse invalid');
1070
1199
  // x = X*Z^-1; y = Y*Z^-1
1071
1200
  return { x: M(x * iz), y: M(y * iz) };
1072
1201
  }
@@ -1076,7 +1205,9 @@ class Point {
1076
1205
  FpIsValidNot0(x); // must be in range 1 <= x,y < P
1077
1206
  FpIsValidNot0(y);
1078
1207
  // y² == x³ + ax + b, equation sides must be equal
1079
- return M(y * y) === koblitz(x) ? this : err('bad point: not on curve');
1208
+ if (M(y * y) !== koblitz(x))
1209
+ throw new Error(E_BADPOINT);
1210
+ return this;
1080
1211
  }
1081
1212
  /** Converts point to 33/65-byte Uint8Array. */
1082
1213
  toBytes(isCompressed = true) {
@@ -1086,7 +1217,7 @@ class Point {
1086
1217
  const x32b = numTo32b(x);
1087
1218
  if (isCompressed)
1088
1219
  return concatBytes(getPrefix(y), x32b);
1089
- return concatBytes(u8of(0x04), x32b, numTo32b(y));
1220
+ return concatBytes(Uint8Array.of(0x04), x32b, numTo32b(y));
1090
1221
  }
1091
1222
  toHex(isCompressed) {
1092
1223
  return bytesToHex(this.toBytes(isCompressed));
@@ -1101,17 +1232,14 @@ Point.BASE = G;
1101
1232
  Point.ZERO = I;
1102
1233
  /** `Q = u1⋅G + u2⋅R`. Verifies Q is not ZERO. Unsafe: non-CT. */
1103
1234
  const doubleScalarMulUns = (R, u1, u2) => {
1104
- return G.multiply(u1, false)
1105
- .add(R.multiply(u2, false))
1106
- .assertValidity();
1235
+ return G.multiply(u1, false).add(R.multiply(u2, false)).assertValidity();
1107
1236
  };
1108
1237
  // Inherits byte validation from bytesToHex(); the || '0' fallback keeps empty input mapped to 0n.
1109
1238
  const bytesToNumBE = (b) => big('0x' + (bytesToHex(b) || '0'));
1110
1239
  // Callers provide monotone slice bounds; subarray() would otherwise clamp or reinterpret them silently.
1111
1240
  const sliceBytesNumBE = (b, from, to) => bytesToNumBE(b.subarray(from, to));
1112
- const B256 = 2n ** 256n; // secp256k1 is weierstrass curve. Equation is x³ + ax + b.
1113
- /** Generic 32-byte big-endian encoder. Must be 0 <= num < B256; call sites need not be field/scalar elements. */
1114
- const numTo32b = (num) => hexToBytes(padh(arange(num, 0n, B256), L2));
1241
+ /** Generic 32-byte big-endian encoder. Must be 0 <= num < 2²⁵⁶; call sites need not be field/scalar elements. */
1242
+ const numTo32b = (num) => hexToBytes(padh(arange(num, 0n, 2n ** 256n), L * 2)); // L*2 = 64 hex chars for a zero-padded 32-byte value
1115
1243
  /** Normalize private key to scalar (bigint). Verifies scalar is in range 1 <= d < N. */
1116
1244
  const secretKeyToScalar = (secretKey) => {
1117
1245
  const num = bytesToNumBE(abytes(secretKey, L, 'secret key'));
@@ -1142,12 +1270,11 @@ const isValidSecretKey = (secretKey) => {
1142
1270
  }
1143
1271
  };
1144
1272
  const isValidPublicKey = (publicKey, isCompressed) => {
1145
- const { publicKey: comp, publicKeyUncompressed } = lengths;
1146
1273
  try {
1147
1274
  const l = publicKey.length;
1148
- if (isCompressed === true && l !== comp)
1275
+ if (isCompressed === true && l !== 33)
1149
1276
  return false;
1150
- if (isCompressed === false && l !== publicKeyUncompressed)
1277
+ if (isCompressed === false && l !== 65)
1151
1278
  return false;
1152
1279
  return !!Point.fromBytes(publicKey);
1153
1280
  }
@@ -1175,12 +1302,11 @@ const _sha = 'SHA-256';
1175
1302
  const hashes = {
1176
1303
  hmacSha256Async: async (key, message) => {
1177
1304
  const s = subtle();
1178
- const name = 'HMAC';
1179
- const k = await s.importKey('raw', key, { name, hash: { name: _sha } }, false, ['sign']);
1180
- return u8n(await s.sign(name, k, message));
1305
+ const k = await s.importKey('raw', key, { name: 'HMAC', hash: _sha }, false, ['sign']);
1306
+ return new Uint8Array(await s.sign('HMAC', k, message));
1181
1307
  },
1182
1308
  hmacSha256: undefined,
1183
- sha256Async: async (msg) => u8n(await subtle().digest(_sha, msg)),
1309
+ sha256Async: async (msg) => new Uint8Array(await subtle().digest(_sha, msg)),
1184
1310
  sha256: undefined,
1185
1311
  };
1186
1312
  /**
@@ -1207,20 +1333,17 @@ const getSharedSecret = (secretKeyA, publicKeyB, isCompressed = true) => {
1207
1333
  // FIPS 186-5 Appendix A.4.1 style key generation reduces a wide random integer mod (n - 1) and adds 1.
1208
1334
  // The 48-byte minimum keeps the secp256k1 bias bound below the appendix's epsilon <= 2^-64 target.
1209
1335
  const randomSecretKey = (seed) => {
1210
- seed = seed === undefined ? randomBytes(lengths.seed) : seed;
1336
+ seed = seed === undefined ? randomBytes(48) : seed;
1211
1337
  abytes(seed);
1212
1338
  // Keep the public range text aligned with the enforced 48-byte FIPS floor.
1213
- if (seed.length < lengths.seed || seed.length > 1024)
1214
- return err('expected 48-1024b', RangeError);
1339
+ if (seed.length < 48 || seed.length > 1024)
1340
+ throw new RangeError('expected 48-1024b');
1215
1341
  const num = M(bytesToNumBE(seed), N - 1n);
1216
1342
  return numTo32b(num + 1n);
1217
1343
  };
1218
1344
  const createKeygen = (getPublicKey) => (seed) => {
1219
1345
  const secretKey = randomSecretKey(seed);
1220
- return {
1221
- secretKey,
1222
- publicKey: getPublicKey(secretKey),
1223
- };
1346
+ return { secretKey, publicKey: getPublicKey(secretKey) };
1224
1347
  };
1225
1348
  /**
1226
1349
  * Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves.
@@ -1231,17 +1354,17 @@ const createKeygen = (getPublicKey) => (seed) => {
1231
1354
  * const hex = etc.bytesToHex(new Uint8Array([1, 2, 3]));
1232
1355
  * ```
1233
1356
  */
1234
- const etc = /* @__PURE__ */ Object.freeze({
1357
+ const etc = /* @__PURE__ */ freeze({
1235
1358
  hexToBytes,
1236
1359
  bytesToHex,
1237
1360
  concatBytes,
1238
1361
  bytesToNumberBE: bytesToNumBE,
1239
1362
  numberToBytesBE: numTo32b,
1240
1363
  mod: M,
1241
- invert: invert, // math utilities; keep public alias type aligned with runtime
1364
+ invert,
1242
1365
  randomBytes,
1243
- secretKeyToScalar: secretKeyToScalar,
1244
- abytes: abytes,
1366
+ secretKeyToScalar,
1367
+ abytes,
1245
1368
  });
1246
1369
  /**
1247
1370
  * Curve-specific key utilities.
@@ -1253,26 +1376,23 @@ const etc = /* @__PURE__ */ Object.freeze({
1253
1376
  * const publicKey = secp.getPublicKey(secretKey);
1254
1377
  * ```
1255
1378
  */
1256
- const utils$2 = /* @__PURE__ */ Object.freeze({
1257
- isValidSecretKey: isValidSecretKey,
1258
- isValidPublicKey: isValidPublicKey,
1259
- randomSecretKey: randomSecretKey, // preserve the optional seeded call
1379
+ const utils$2 = /* @__PURE__ */ freeze({
1380
+ isValidSecretKey,
1381
+ isValidPublicKey,
1382
+ randomSecretKey,
1260
1383
  });
1261
1384
  // Schnorr signatures are superior to ECDSA from above. Below is Schnorr-specific BIP0340 code.
1262
1385
  // https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
1263
1386
  // Internal BIP340 tag names are ASCII-only here, so charCodeAt() is enough; this is not a general UTF-8 encoder.
1264
1387
  const getTag = (tag) => Uint8Array.from('BIP0340/' + tag, (c) => c.charCodeAt(0));
1265
- const T_AUX = 'aux';
1266
- const T_NONCE = 'nonce';
1267
- const T_CHALLENGE = 'challenge';
1268
1388
  // Both SHA-256 provider slots are configurable, so tag hashing still goes through the checked
1269
1389
  // wrappers even though the built-in defaults are deterministic and the tag bytes are ASCII-only.
1270
1390
  const taggedHash = (tag, ...messages) => {
1271
- const tagH = gh('sha256', getTag(tag));
1272
- return gh('sha256', concatBytes(tagH, tagH, ...messages));
1391
+ const tagH = callHash('sha256', getTag(tag));
1392
+ return callHash('sha256', concatBytes(tagH, tagH, ...messages));
1273
1393
  };
1274
1394
  // Async twin of taggedHash with the same checked provider boundary.
1275
- const taggedHashAsync = (tag, ...messages) => gha('sha256Async', getTag(tag)).then((tagH) => gha('sha256Async', concatBytes(tagH, tagH, ...messages)));
1395
+ const taggedHashAsync = (tag, ...messages) => callHashAsync('sha256Async', getTag(tag)).then((tagH) => callHashAsync('sha256Async', concatBytes(tagH, tagH, ...messages)));
1276
1396
  // BIP340 PubKey(sk) = bytes(d'⋅G), where bytes(P) is bytes(x(P)); signing also normalizes
1277
1397
  // d to the equivalent scalar whose point has even y so the x-only public key stays canonical.
1278
1398
  const extpubSchnorr = (priv) => {
@@ -1284,8 +1404,8 @@ const extpubSchnorr = (priv) => {
1284
1404
  return { d, px };
1285
1405
  };
1286
1406
  const bytesModN = (bytes) => modN(bytesToNumBE(bytes));
1287
- const challenge = (...args) => bytesModN(taggedHash(T_CHALLENGE, ...args));
1288
- const challengeAsync = async (...args) => bytesModN(await taggedHashAsync(T_CHALLENGE, ...args));
1407
+ const challenge = (...args) => bytesModN(taggedHash('challenge', ...args));
1408
+ const challengeAsync = async (...args) => bytesModN(await taggedHashAsync('challenge', ...args));
1289
1409
  /** Schnorr public key is just `x` coordinate of Point as per BIP340. */
1290
1410
  const pubSchnorr = (secretKey) => {
1291
1411
  return extpubSchnorr(secretKey).px; // d'=int(sk). Fail if d'=0 or d'≥n. Ret bytes(d'⋅G)
@@ -1293,13 +1413,14 @@ const pubSchnorr = (secretKey) => {
1293
1413
  const keygenSchnorr = /* @__PURE__ */ createKeygen(pubSchnorr);
1294
1414
  // Common preparation fn for both sync and async signing
1295
1415
  const prepSigSchnorr = (message, secretKey, auxRand) => {
1416
+ const m = snapshotBytes(message, 'message');
1296
1417
  const { px, d } = extpubSchnorr(secretKey);
1297
- return { m: abytes(message), px, d, a: abytes(auxRand, L) };
1418
+ return { m, px, d, a: abytes(auxRand, L) };
1298
1419
  };
1299
1420
  const extractK = (rand) => {
1300
1421
  const k_ = bytesModN(rand); // Let k' = int(rand) mod n
1301
1422
  if (k_ === 0n)
1302
- err('sign failed: k is zero'); // Fail if k' = 0.
1423
+ throw new Error('sign failed: k is zero'); // Fail if k' = 0.
1303
1424
  const { px, d } = extpubSchnorr(numTo32b(k_)); // Let R = k'⋅G.
1304
1425
  return { rx: px, k: d };
1305
1426
  };
@@ -1315,73 +1436,78 @@ const E_INVSIG = 'invalid signature produced';
1315
1436
  */
1316
1437
  const signSchnorr = (message, secretKey, auxRand = randomBytes(L)) => {
1317
1438
  const { m, px, d, a } = prepSigSchnorr(message, secretKey, auxRand);
1318
- const aux = taggedHash(T_AUX, a);
1319
1439
  // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
1320
- const t = numTo32b(d ^ bytesToNumBE(aux));
1440
+ const t = numTo32b(d ^ bytesToNumBE(taggedHash('aux', a)));
1321
1441
  // Let rand = hash/nonce(t || bytes(P) || m)
1322
- const rand = taggedHash(T_NONCE, t, px, m);
1323
- const { rx, k } = extractK(rand);
1442
+ const { rx, k } = extractK(taggedHash('nonce', t, px, m));
1324
1443
  // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
1325
- const e = challenge(rx, px, m);
1326
- const sig = createSigSchnorr(k, rx, e, d);
1444
+ const sig = createSigSchnorr(k, rx, challenge(rx, px, m), d);
1327
1445
  // If Verify(bytes(P), m, sig) (see below) returns failure, abort
1328
1446
  if (!verifySchnorr(sig, m, px))
1329
- err(E_INVSIG);
1447
+ throw new Error(E_INVSIG);
1330
1448
  return sig;
1331
1449
  };
1332
1450
  const signSchnorrAsync = async (message, secretKey, auxRand = randomBytes(L)) => {
1333
1451
  const { m, px, d, a } = prepSigSchnorr(message, secretKey, auxRand);
1334
- const aux = await taggedHashAsync(T_AUX, a);
1335
1452
  // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
1336
- const t = numTo32b(d ^ bytesToNumBE(aux));
1453
+ const t = numTo32b(d ^ bytesToNumBE(await taggedHashAsync('aux', a)));
1337
1454
  // Let rand = hash/nonce(t || bytes(P) || m)
1338
- const rand = await taggedHashAsync(T_NONCE, t, px, m);
1339
- const { rx, k } = extractK(rand);
1455
+ const { rx, k } = extractK(await taggedHashAsync('nonce', t, px, m));
1340
1456
  // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
1341
- const e = await challengeAsync(rx, px, m);
1342
- const sig = createSigSchnorr(k, rx, e, d);
1457
+ const sig = createSigSchnorr(k, rx, await challengeAsync(rx, px, m), d);
1343
1458
  // If Verify(bytes(P), m, sig) (see below) returns failure, abort
1344
1459
  if (!(await verifySchnorrAsync(sig, m, px)))
1345
- err(E_INVSIG);
1460
+ throw new Error(E_INVSIG);
1346
1461
  return sig;
1347
1462
  };
1348
1463
  const callSyncAsyncFn = (res, later) => {
1349
1464
  return res instanceof Promise ? res.then(later) : later(res);
1350
1465
  };
1351
1466
  const _verifSchnorr = (signature, message, publicKey, challengeFn) => {
1352
- const sig = abytes(signature, L2, 'signature');
1467
+ const sig = abytes(signature, 64, 'signature');
1353
1468
  const msg = abytes(message, undefined, 'message');
1354
1469
  const pub = abytes(publicKey, L, 'publicKey');
1470
+ let P_;
1471
+ let r;
1472
+ let s;
1473
+ let chalInput; // challenge preimage bytes(r) || bytes(P) || m
1355
1474
  try {
1356
1475
  // lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
1357
1476
  // Fail if x ≥ p. Let c = x³ + 7 mod p.
1358
1477
  const x = bytesToNumBE(pub);
1359
- const y = lift_x(x); // lift_x already returns the unique even root required by BIP340.
1360
- const P_ = new Point(x, y, 1n).assertValidity();
1361
- const px = numTo32b(P_.toAffine().x);
1478
+ P_ = lift_x(x); // lift_x returns the validated even-y point required by BIP340.
1362
1479
  // P = lift_x(int(pk)); fail if that fails
1363
- const r = sliceBytesNumBE(sig, 0, L); // Let r = int(sig[0:32]); fail if r ≥ p.
1364
- arange(r, 1n, P);
1365
- const s = sliceBytesNumBE(sig, L, L2); // Let s = int(sig[32:64]); fail if s ≥ n.
1480
+ r = FpIsValidNot0(sliceBytesNumBE(sig, 0, L)); // Let r = int(sig[0:32]); fail if r ≥ p.
1481
+ // Let s = int(sig[32:64]); fail if s ≥ n.
1366
1482
  // Stricter than BIP-340/libsecp256k1, which only reject s >= n. Honest signing reaches
1367
1483
  // s = 0 only with negligible probability (k + e*d ≡ 0 mod n), so treat zero-s inputs as
1368
1484
  // crafted edge cases and fail closed instead of carrying that extra verification surface.
1369
- arange(s, 1n, N);
1370
- const i = concatBytes(numTo32b(r), px, msg);
1371
- // int(challenge(bytes(r)||bytes(P)||m))%n
1372
- return callSyncAsyncFn(challengeFn(i), (e) => {
1373
- const { x, y } = doubleScalarMulUns(P_, s, modN(-e)).toAffine(); // R = s⋅G - e⋅P
1374
- if (!isEven(y) || x !== r)
1375
- return false; // -eP == (n-e)P
1376
- return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
1377
- });
1485
+ s = FnIsValidNot0(sliceBytesNumBE(sig, L, 64));
1486
+ // lift_x validated x < P, so the 32-byte input encoding equals bytes(P.x) exactly.
1487
+ chalInput = concatBytes(numTo32b(r), pub, msg);
1378
1488
  }
1379
1489
  catch (error) {
1380
1490
  return false;
1381
1491
  }
1492
+ // Hash-provider errors (unset hashes.sha256, missing crypto.subtle, bad provider digests)
1493
+ // stay outside the catch above: backend misconfiguration is not an "invalid signature"
1494
+ // result, so it throws / rejects instead of becoming false.
1495
+ // int(challenge(bytes(r)||bytes(P)||m))%n
1496
+ return callSyncAsyncFn(challengeFn(chalInput), (e) => {
1497
+ try {
1498
+ const { x, y } = doubleScalarMulUns(P_, s, modN(-e)).toAffine(); // R = s⋅G - e⋅P
1499
+ if (!isEven(y) || x !== r)
1500
+ return false; // -eP == (n-e)P
1501
+ return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
1502
+ }
1503
+ catch (error) {
1504
+ return false; // is_infinite(R) throws inside doubleScalarMulUns
1505
+ }
1506
+ });
1382
1507
  };
1383
- /** Verifies Schnorr signature. Sync wrapper returns false for post-validation failures
1384
- * after the initial byte checks. */
1508
+ /** Verifies Schnorr signature. Invalid points, scalars and failed curve checks return false;
1509
+ * hash-backend misconfiguration (e.g. unset hashes.sha256) throws instead, since it is a
1510
+ * runtime/backend error, not an "invalid signature" result. */
1385
1511
  const verifySchnorr = (s, m, p) => _verifSchnorr(s, m, p, challenge);
1386
1512
  /** Async Schnorr verification. Curve/encoding failures after the initial byte checks still
1387
1513
  * become false, but async backend failures reject the promise. Missing crypto.subtle is a
@@ -1403,7 +1529,7 @@ const verifySchnorrAsync = async (s, m, p) => _verifSchnorr(s, m, p, challengeAs
1403
1529
  * const isValid = secp.schnorr.verify(sig, message, publicKey);
1404
1530
  * ```
1405
1531
  */
1406
- const schnorr = /* @__PURE__ */ Object.freeze({
1532
+ const schnorr = /* @__PURE__ */ freeze({
1407
1533
  keygen: keygenSchnorr,
1408
1534
  getPublicKey: pubSchnorr,
1409
1535
  sign: signSchnorr,
@@ -1413,18 +1539,14 @@ const schnorr = /* @__PURE__ */ Object.freeze({
1413
1539
  });
1414
1540
  // ## Precomputes
1415
1541
  // --------------
1416
- const W = 8; // W is window size
1417
- const scalarBits = 256;
1418
- const pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop
1419
- const pwindowSize = 2 ** (W - 1); // 128 for W=8
1420
1542
  const precompute = () => {
1421
1543
  const points = [];
1422
1544
  let p = G;
1423
1545
  let b = p;
1424
- for (let w = 0; w < pwindows; w++) {
1546
+ for (let w = 0; w < 33; w++) {
1425
1547
  b = p;
1426
1548
  points.push(b);
1427
- for (let i = 1; i < pwindowSize; i++) {
1549
+ for (let i = 1; i < 128; i++) {
1428
1550
  b = b.add(p);
1429
1551
  points.push(b);
1430
1552
  } // i=1, bc we skip 0
@@ -1453,37 +1575,32 @@ const wNAF = (n) => {
1453
1575
  const comp = Gpows || (Gpows = precompute());
1454
1576
  let p = I;
1455
1577
  let f = G; // f must be G, or could become I in the end
1456
- const pow_2_w = 2 ** W; // 256 for W=8
1457
- const maxNum = pow_2_w; // 256 for W=8
1458
- const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111
1459
- const shiftBy = big(W); // 8 for W=8
1460
- for (let w = 0; w < pwindows; w++) {
1461
- let wbits = Number(n & mask); // extract W bits.
1462
- n >>= shiftBy; // shift number by W bits.
1578
+ for (let w = 0; w < 33; w++) {
1579
+ let wbits = Number(n & 255n); // extract W=8 bits.
1580
+ n >>= 8n; // shift number by W=8 bits.
1463
1581
  // We use negative indexes to reduce size of precomputed table by 2x.
1464
1582
  // Instead of needing precomputes 0..256, we only calculate them for 0..128.
1465
1583
  // If an index > 128 is found, we do (256-index) - where 256 is next window.
1466
1584
  // Naive: index +127 => 127, +224 => 224
1467
1585
  // Optimized: index +127 => 127, +224 => 256-32
1468
- if (wbits > pwindowSize) {
1469
- wbits -= maxNum;
1586
+ if (wbits > 128) {
1587
+ wbits -= 256;
1470
1588
  n += 1n;
1471
1589
  }
1472
- const off = w * pwindowSize;
1473
- const offF = off; // offsets, evaluate both
1590
+ const off = w * 128;
1474
1591
  const offP = off + Math.abs(wbits) - 1;
1475
- const isEven = w % 2 !== 0; // conditions, evaluate both
1592
+ const isOddW = w % 2 !== 0; // conditions, evaluate both; alternates fake-add sign per window
1476
1593
  const isNeg = wbits < 0;
1477
1594
  if (wbits === 0) {
1478
- // off == I: can't add it. Adding random offF instead.
1479
- f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point
1595
+ // off == I: can't add it. Add the first point in this window to the fake accumulator.
1596
+ f = f.add(ctneg(isOddW, comp[off])); // bits are 0: add garbage to fake point
1480
1597
  }
1481
1598
  else {
1482
1599
  p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point
1483
1600
  }
1484
1601
  }
1485
1602
  if (n !== 0n)
1486
- err('invalid wnaf');
1603
+ throw new Error('invalid wnaf');
1487
1604
  return { p, f }; // return both real and fake points for JIT/leakage-shape symmetry
1488
1605
  };
1489
1606
 
@@ -2403,10 +2520,10 @@ class HdNode {
2403
2520
  return (async () => (await this.identifier).subarray(0, 4))();
2404
2521
  }
2405
2522
  async hash160(data) {
2406
- const hash = await createHash(data, 'SHA-256');
2523
+ const hash = await createHash(data, "SHA-256");
2407
2524
  return (await createRIPEMD160())
2408
2525
  .update(new Uint8Array(hash))
2409
- .digest('binary');
2526
+ .digest("binary");
2410
2527
  }
2411
2528
  get isNeutered() {
2412
2529
  return this.#privateKey === undefined;
@@ -2416,24 +2533,24 @@ class HdNode {
2416
2533
  }
2417
2534
  fromPrivateKey(privateKey, chainCode, network) {
2418
2535
  if (!privateKeyVerify(privateKey))
2419
- throw new TypeError('Private key not in range [1, n)');
2536
+ throw new TypeError("Private key not in range [1, n)");
2420
2537
  const publicKey = publicKeyCreate(privateKey, true);
2421
2538
  return new HdNode(privateKey, publicKey, publicKey.slice(1), network);
2422
2539
  }
2423
2540
  fromPublicKey(publicKey, chainCode, network) {
2424
2541
  // verify the X coordinate is a point on the curve
2425
2542
  if (!publicKeyVerify(publicKey))
2426
- throw new TypeError('Point is not on the curve');
2543
+ throw new TypeError("Point is not on the curve");
2427
2544
  return new HdNode(undefined, publicKey, chainCode, network);
2428
2545
  }
2429
2546
  async fromSeed(seed, network) {
2430
2547
  if (seed.length < 16)
2431
- throw new TypeError('Seed should be at least 128 bits');
2548
+ throw new TypeError("Seed should be at least 128 bits");
2432
2549
  if (seed.length > 64)
2433
- throw new TypeError('Seed should be at most 512 bits');
2434
- let hash = (await createHMAC(createSHA512(), new TextEncoder().encode('Bitcoin seed')))
2550
+ throw new TypeError("Seed should be at most 512 bits");
2551
+ let hash = (await createHMAC(createSHA512(), new TextEncoder().encode("Bitcoin seed")))
2435
2552
  .update(seed)
2436
- .digest('binary');
2553
+ .digest("binary");
2437
2554
  const privateKey = hash.subarray(0, 32);
2438
2555
  const chainCode = hash.subarray(32);
2439
2556
  return this.fromPrivateKey(privateKey, chainCode, network);
@@ -2451,7 +2568,7 @@ class HdNode {
2451
2568
  this.#chainCode,
2452
2569
  ];
2453
2570
  if (!this.isNeutered) {
2454
- set.push(new TextEncoder().encode('0'));
2571
+ set.push(new TextEncoder().encode("0"));
2455
2572
  set.push(new Uint8Array(this.privateKey));
2456
2573
  }
2457
2574
  else {
@@ -2461,7 +2578,7 @@ class HdNode {
2461
2578
  }
2462
2579
  toWIF() {
2463
2580
  if (!this.#privateKey)
2464
- throw new TypeError('Missing private key');
2581
+ throw new TypeError("Missing private key");
2465
2582
  return wif.encode(this.#network.wif, this.#privateKey, true);
2466
2583
  }
2467
2584
  // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
@@ -2471,10 +2588,10 @@ class HdNode {
2471
2588
  // Hardened child
2472
2589
  if (isHardened) {
2473
2590
  if (this.isNeutered)
2474
- throw new TypeError('Missing private key for hardened child key');
2591
+ throw new TypeError("Missing private key for hardened child key");
2475
2592
  // data = 0x00 || ser256(kpar) || ser32(index)
2476
2593
  data = index$3([
2477
- new TextEncoder().encode('0'),
2594
+ new TextEncoder().encode("0"),
2478
2595
  this.privateKey,
2479
2596
  new TextEncoder().encode(index.toString()),
2480
2597
  ]);
@@ -2487,7 +2604,7 @@ class HdNode {
2487
2604
  }
2488
2605
  const hash = (await createHMAC(createSHA512(), this.#chainCode))
2489
2606
  .update(data)
2490
- .digest('binary');
2607
+ .digest("binary");
2491
2608
  const privateKey = hash.subarray(0, 32);
2492
2609
  const chainCode = hash.subarray(32);
2493
2610
  // if parse256(privateKey) >= n, proceed with the next value for i
@@ -2514,10 +2631,10 @@ class HdNode {
2514
2631
  return this.derive(index + HIGHEST_BIT);
2515
2632
  }
2516
2633
  async derivePath(path) {
2517
- let splitPath = path.split('/');
2518
- if (splitPath[0] === 'm') {
2634
+ let splitPath = path.split("/");
2635
+ if (splitPath[0] === "m") {
2519
2636
  if (this.#parentFingerprint)
2520
- throw new TypeError('Expected master, got child');
2637
+ throw new TypeError("Expected master, got child");
2521
2638
  splitPath = splitPath.slice(1);
2522
2639
  }
2523
2640
  let prevHd = this;
@@ -2549,16 +2666,16 @@ class HdNode {
2549
2666
  const k = privateKey ? 0 : result[5];
2550
2667
  const chainCode = result[4];
2551
2668
  if (version !== network.bip32.private && version !== network.bip32.public)
2552
- throw new TypeError('Invalid network version');
2669
+ throw new TypeError("Invalid network version");
2553
2670
  if (depth === 0) {
2554
2671
  if (parentFingerprint !== 0)
2555
- throw new TypeError('Invalid parent fingerprint');
2672
+ throw new TypeError("Invalid parent fingerprint");
2556
2673
  }
2557
2674
  if (depth === 0 && index !== 0)
2558
- throw new TypeError('Invalid index');
2675
+ throw new TypeError("Invalid index");
2559
2676
  if (version === network.bip32.private) {
2560
2677
  if (k !== 0x00)
2561
- throw new TypeError('Invalid private key');
2678
+ throw new TypeError("Invalid private key");
2562
2679
  return new HdNode(privateKey, undefined, chainCode, network, depth, index, parentFingerprint);
2563
2680
  }
2564
2681
  return new HdNode(undefined,
@@ -4910,11 +5027,8 @@ class MultiSignature {
4910
5027
  signature = signature || this.signature;
4911
5028
  if (!signature)
4912
5029
  throw ReferenceError("signature undefined");
4913
- this.#multiSignature = typedArrayConcat([
4914
- index$4.encode(this.version),
4915
- index$4.encode(this.multiCodec),
4916
- signature,
4917
- ]);
5030
+ const writer = new BinaryWriter(varUintLength(this.version) + varUintLength(this.multiCodec) + signature.length);
5031
+ this.#multiSignature = writer.writeVarUint(this.version).writeVarUint(this.multiCodec).writeBytes(signature).finish();
4918
5032
  return this.multiSignature;
4919
5033
  }
4920
5034
  /**
@@ -4927,12 +5041,11 @@ class MultiSignature {
4927
5041
  this.#multiSignature = multiSignature;
4928
5042
  if (!this.multiSignature)
4929
5043
  throw ReferenceError("multiSignature undefined");
4930
- let buffer = this.multiSignature;
4931
- const version = index$4.decode(buffer);
4932
- buffer = buffer.subarray(index$4.decode.bytes);
4933
- const codec = index$4.decode(buffer);
4934
- buffer = buffer.subarray(index$4.decode.bytes);
4935
- const signature = buffer.subarray(0, buffer.length);
5044
+ const reader = new BinaryReader(this.multiSignature);
5045
+ // Keep legacy padded-header acceptance; do not change signature wire rules.
5046
+ const version = reader.readVarUint(false);
5047
+ const codec = reader.readVarUint(false);
5048
+ const signature = reader.readBytes(reader.remaining);
4936
5049
  console.log("[decode] extracted signature length:", signature.length);
4937
5050
  console.log("[decode] extracted signature (hex):", Buffer.from(signature).toString("hex"));
4938
5051
  if (version !== this.version)
@@ -4950,7 +5063,7 @@ class MultiSignature {
4950
5063
  return this.multiSignature.toString();
4951
5064
  }
4952
5065
  fromString(string) {
4953
- return this.decode(new Uint8Array(string.split(",")));
5066
+ return this.decode(new Uint8Array(string.split(",").map(Number)));
4954
5067
  }
4955
5068
  toBs58() {
4956
5069
  return base58$1.encode(this.multiSignature);
@@ -5025,17 +5138,26 @@ class MultiHDNode extends HDWallet {
5025
5138
  get id() {
5026
5139
  return base58check.encode(index$3([
5027
5140
  new TextEncoder().encode(this.version.toString()),
5028
- this.account(0).hdnode.neutered.publicKey
5141
+ this.account(0).hdnode.neutered.publicKey,
5029
5142
  ]));
5030
5143
  }
5031
5144
  get multiWIF() {
5032
5145
  return this.toMultiWif();
5033
5146
  }
5034
5147
  async fromId(id) {
5035
- let buffer = (await base58check.decode(id)).data;
5036
- index$4.decode(buffer);
5037
- buffer = buffer.slice(index$4.decode.bytes);
5038
- this.fromPublicKey(buffer, null, this.networkName);
5148
+ const buffer = (await base58check.decode(id)).data;
5149
+ const reader = new BinaryReader(buffer);
5150
+ // IDs contain two framed fields: textual version and compressed public key.
5151
+ // Keep legacy padded length prefixes readable without changing generated IDs.
5152
+ const version = reader.readFrame(false);
5153
+ const publicKey = reader.readFrame(false);
5154
+ const expectedVersion = new TextEncoder().encode(this.version.toString());
5155
+ if (reader.remaining !== 0 ||
5156
+ version.length !== expectedVersion.length ||
5157
+ !version.every((byte, index) => byte === expectedVersion[index]) ||
5158
+ publicKey.length !== 33)
5159
+ throw new Error("invalid wallet ID");
5160
+ await this.fromPublicKey(publicKey, null, this.networkName);
5039
5161
  }
5040
5162
  async import(password, encrypted) {
5041
5163
  const { prefix, data } = await base58check.decode(encrypted);
@@ -5064,22 +5186,20 @@ class MultiHDNode extends HDWallet {
5064
5186
  return c.testnet;
5065
5187
  else
5066
5188
  return p;
5067
- }, networks['leofcoin']);
5189
+ }, networks["leofcoin"]);
5068
5190
  if (version !== this.network.version)
5069
- throw new Error('invalid version');
5191
+ throw new Error("invalid version");
5070
5192
  return this.fromPrivateKey(privateKey, undefined, this.network);
5071
5193
  }
5072
5194
  toMultiWif() {
5073
5195
  return index$1.encode(this.network.version, this.network.multiCodec, this.privateKey);
5074
5196
  }
5075
5197
  sign(hash) {
5076
- return new MultiSignature(this.version, this.network.multiCodec)
5077
- .sign(hash, this.privateKey);
5198
+ return new MultiSignature(this.version, this.network.multiCodec).sign(hash, this.privateKey);
5078
5199
  }
5079
5200
  verify(multiSignature, hash) {
5080
5201
  const publicKey = this.publicKey?.length === 33 ? this.publicKey.slice(1) : this.publicKey;
5081
- return new MultiSignature(this.version, this.network.multiCodec)
5082
- .verify(multiSignature, hash, publicKey);
5202
+ return new MultiSignature(this.version, this.network.multiCodec).verify(multiSignature, hash, publicKey);
5083
5203
  }
5084
5204
  }
5085
5205
 
@@ -8336,7 +8456,7 @@ class Identity {
8336
8456
  this.selectedAccount = new TextDecoder().decode(selected);
8337
8457
  }
8338
8458
  else {
8339
- const importee = await import(/* webpackChunkName: "generate-account" */ './index-Bxr5Iztg.js');
8459
+ const importee = await import(/* webpackChunkName: "generate-account" */ './index-dTQVgkpf.js');
8340
8460
  const { identity, accounts } = await importee.default(password, this.network);
8341
8461
  if (fresh) {
8342
8462
  await globalThis.accountStore.clear();
@@ -8399,4 +8519,4 @@ class Identity {
8399
8519
  }
8400
8520
  }
8401
8521
 
8402
- export { Identity as I, MultiWallet as M, base58$1 as a, base as b, index as c, index$2 as d, index$4 as e, createSHA512 as f, createSHA384 as g, createSHA256 as h, index$3 as i, createSHA224 as j, createSHA1 as k, encrypt as l, getDefaultExportFromCjs as m, resolveAccountWallets as r };
8522
+ export { BinaryReader as B, Identity as I, MultiWallet as M, base58$1 as a, base as b, index as c, index$2 as d, BinaryWriter as e, createSHA512 as f, createSHA384 as g, createSHA256 as h, index$3 as i, createSHA224 as j, createSHA1 as k, encrypt as l, getDefaultExportFromCjs as m, resolveAccountWallets as r, varUintLength as v };