@did-btcr2/method 0.33.0 → 0.35.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 (88) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/browser.js +371 -119
  3. package/dist/browser.mjs +371 -119
  4. package/dist/cjs/index.js +326 -81
  5. package/dist/esm/core/aggregation/cohort.js +5 -1
  6. package/dist/esm/core/aggregation/cohort.js.map +1 -1
  7. package/dist/esm/core/aggregation/participant.js +25 -8
  8. package/dist/esm/core/aggregation/participant.js.map +1 -1
  9. package/dist/esm/core/aggregation/runner/aggregation-runner.js +66 -0
  10. package/dist/esm/core/aggregation/runner/aggregation-runner.js.map +1 -0
  11. package/dist/esm/core/aggregation/runner/index.js +1 -0
  12. package/dist/esm/core/aggregation/runner/index.js.map +1 -1
  13. package/dist/esm/core/aggregation/runner/participant-runner.js +9 -1
  14. package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
  15. package/dist/esm/core/aggregation/runner/service-runner.js +4 -1
  16. package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
  17. package/dist/esm/core/aggregation/service.js +4 -4
  18. package/dist/esm/core/aggregation/service.js.map +1 -1
  19. package/dist/esm/core/aggregation/signer.js +33 -0
  20. package/dist/esm/core/aggregation/signer.js.map +1 -0
  21. package/dist/esm/core/aggregation/signing-session.js +34 -11
  22. package/dist/esm/core/aggregation/signing-session.js.map +1 -1
  23. package/dist/esm/core/aggregation/transport/in-memory.js +149 -0
  24. package/dist/esm/core/aggregation/transport/in-memory.js.map +1 -0
  25. package/dist/esm/core/aggregation/transport/index.js +1 -0
  26. package/dist/esm/core/aggregation/transport/index.js.map +1 -1
  27. package/dist/esm/core/beacon/beacon.js +10 -8
  28. package/dist/esm/core/beacon/beacon.js.map +1 -1
  29. package/dist/esm/core/beacon/cas-beacon.js +4 -4
  30. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  31. package/dist/esm/core/beacon/factory.js +1 -1
  32. package/dist/esm/core/beacon/singleton-beacon.js +4 -4
  33. package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
  34. package/dist/esm/core/beacon/smt-beacon.js +4 -4
  35. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  36. package/dist/esm/index.js +1 -0
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
  39. package/dist/types/core/aggregation/participant.d.ts +17 -4
  40. package/dist/types/core/aggregation/participant.d.ts.map +1 -1
  41. package/dist/types/core/aggregation/runner/aggregation-runner.d.ts +56 -0
  42. package/dist/types/core/aggregation/runner/aggregation-runner.d.ts.map +1 -0
  43. package/dist/types/core/aggregation/runner/index.d.ts +1 -0
  44. package/dist/types/core/aggregation/runner/index.d.ts.map +1 -1
  45. package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
  46. package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
  47. package/dist/types/core/aggregation/service.d.ts +10 -4
  48. package/dist/types/core/aggregation/service.d.ts.map +1 -1
  49. package/dist/types/core/aggregation/signer.d.ts +50 -0
  50. package/dist/types/core/aggregation/signer.d.ts.map +1 -0
  51. package/dist/types/core/aggregation/signing-session.d.ts +13 -5
  52. package/dist/types/core/aggregation/signing-session.d.ts.map +1 -1
  53. package/dist/types/core/aggregation/transport/in-memory.d.ts +64 -0
  54. package/dist/types/core/aggregation/transport/in-memory.d.ts.map +1 -0
  55. package/dist/types/core/aggregation/transport/index.d.ts +1 -0
  56. package/dist/types/core/aggregation/transport/index.d.ts.map +1 -1
  57. package/dist/types/core/beacon/beacon.d.ts +12 -10
  58. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  59. package/dist/types/core/beacon/cas-beacon.d.ts +4 -4
  60. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  61. package/dist/types/core/beacon/factory.d.ts +3 -3
  62. package/dist/types/core/beacon/factory.d.ts.map +1 -1
  63. package/dist/types/core/beacon/singleton-beacon.d.ts +4 -4
  64. package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -1
  65. package/dist/types/core/beacon/smt-beacon.d.ts +4 -4
  66. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  67. package/dist/types/core/resolver.d.ts +1 -1
  68. package/dist/types/index.d.ts +1 -0
  69. package/dist/types/index.d.ts.map +1 -1
  70. package/package.json +5 -5
  71. package/src/core/aggregation/cohort.ts +5 -1
  72. package/src/core/aggregation/participant.ts +38 -12
  73. package/src/core/aggregation/runner/aggregation-runner.ts +96 -0
  74. package/src/core/aggregation/runner/index.ts +1 -0
  75. package/src/core/aggregation/runner/participant-runner.ts +9 -1
  76. package/src/core/aggregation/runner/service-runner.ts +4 -1
  77. package/src/core/aggregation/service.ts +12 -6
  78. package/src/core/aggregation/signer.ts +67 -0
  79. package/src/core/aggregation/signing-session.ts +34 -11
  80. package/src/core/aggregation/transport/in-memory.ts +178 -0
  81. package/src/core/aggregation/transport/index.ts +1 -0
  82. package/src/core/beacon/beacon.ts +12 -10
  83. package/src/core/beacon/cas-beacon.ts +4 -4
  84. package/src/core/beacon/factory.ts +3 -3
  85. package/src/core/beacon/singleton-beacon.ts +4 -4
  86. package/src/core/beacon/smt-beacon.ts +4 -4
  87. package/src/core/resolver.ts +1 -1
  88. package/src/index.ts +1 -0
package/dist/cjs/index.js CHANGED
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  AggregationParticipant: () => AggregationParticipant,
41
41
  AggregationParticipantError: () => AggregationParticipantError,
42
42
  AggregationParticipantRunner: () => AggregationParticipantRunner,
43
+ AggregationRunner: () => AggregationRunner,
43
44
  AggregationService: () => AggregationService,
44
45
  AggregationServiceError: () => AggregationServiceError,
45
46
  AggregationServiceRunner: () => AggregationServiceRunner,
@@ -47,7 +48,6 @@ __export(index_exports, {
47
48
  BECH32M_CHARS: () => BECH32M_CHARS,
48
49
  BTCR2_DID_DOCUMENT_CONTEXT: () => BTCR2_DID_DOCUMENT_CONTEXT,
49
50
  BaseMessage: () => BaseMessage,
50
- Beacon: () => Beacon,
51
51
  BeaconError: () => BeaconError,
52
52
  BeaconFactory: () => BeaconFactory,
53
53
  BeaconSignalDiscovery: () => BeaconSignalDiscovery,
@@ -82,8 +82,11 @@ __export(index_exports, {
82
82
  HttpTransportError: () => HttpTransportError,
83
83
  ID_PLACEHOLDER_VALUE: () => ID_PLACEHOLDER_VALUE,
84
84
  Identifier: () => Identifier,
85
+ InMemoryBus: () => InMemoryBus,
85
86
  InMemoryRateLimitStore: () => InMemoryRateLimitStore,
87
+ InMemoryTransport: () => InMemoryTransport,
86
88
  InboxBuffer: () => InboxBuffer,
89
+ KeyPairAggregationSigner: () => KeyPairAggregationSigner,
87
90
  NONCE_CONTRIBUTION: () => NONCE_CONTRIBUTION,
88
91
  NonceCache: () => NonceCache,
89
92
  NostrTransport: () => NostrTransport,
@@ -104,6 +107,7 @@ __export(index_exports, {
104
107
  ServiceCohortPhase: () => ServiceCohortPhase,
105
108
  SigningSessionError: () => SigningSessionError,
106
109
  SigningSessionPhase: () => SigningSessionPhase,
110
+ SinglePartyBeacon: () => SinglePartyBeacon,
107
111
  SingletonBeacon: () => SingletonBeacon,
108
112
  SingletonBeaconError: () => SingletonBeaconError,
109
113
  StaticFeeEstimator: () => StaticFeeEstimator,
@@ -221,6 +225,7 @@ function getBeaconStrategy(type) {
221
225
  }
222
226
 
223
227
  // src/core/aggregation/cohort.ts
228
+ var import_bitcoin = require("@did-btcr2/bitcoin");
224
229
  var import_common3 = require("@did-btcr2/common");
225
230
  var import_smt2 = require("@did-btcr2/smt");
226
231
  var import_secp256k1 = require("@noble/curves/secp256k1.js");
@@ -322,7 +327,7 @@ var AggregationCohort = class {
322
327
  }
323
328
  const keyAggContext = (0, import_musig2.keyAggregate)(this.#cohortKeys);
324
329
  const aggPubkey = (0, import_musig2.keyAggExport)(keyAggContext);
325
- const payment = (0, import_btc_signer.p2tr)(aggPubkey);
330
+ const payment = (0, import_btc_signer.p2tr)(aggPubkey, void 0, (0, import_bitcoin.getNetwork)(this.network));
326
331
  this.tapTweak = import_secp256k1.schnorr.utils.taggedHash("TapTweak", aggPubkey);
327
332
  if (!payment.address) {
328
333
  throw new AggregationCohortError(
@@ -593,6 +598,7 @@ var SigningSessionPhase = /* @__PURE__ */ ((SigningSessionPhase2) => {
593
598
  })(SigningSessionPhase || {});
594
599
 
595
600
  // src/core/aggregation/signing-session.ts
601
+ var import_keypair = require("@did-btcr2/keypair");
596
602
  var import_btc_signer2 = require("@scure/btc-signer");
597
603
  var musig2 = __toESM(require("@scure/btc-signer/musig2"), 1);
598
604
  var BeaconSigningSession = class {
@@ -616,8 +622,14 @@ var BeaconSigningSession = class {
616
622
  signature;
617
623
  /** Current signing session phase. */
618
624
  phase;
619
- /** Participant's secret nonce (held only by the participant during signing). */
620
- secretNonce;
625
+ /**
626
+ * Participant's MuSig2 secret nonce, held only on the participant side
627
+ * between {@link generateNonceContribution} and {@link generatePartialSignature}.
628
+ * Private and cleared on every terminal path (success, failure, or teardown
629
+ * via {@link clearSecrets}) so a spent or abandoned nonce cannot be reused or
630
+ * serialized.
631
+ */
632
+ #secretNonce;
621
633
  constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }) {
622
634
  this.id = id || crypto.randomUUID();
623
635
  this.cohort = cohort;
@@ -769,22 +781,24 @@ var BeaconSigningSession = class {
769
781
  generateNonceContribution(participantPublicKey, participantSecretKey) {
770
782
  const aggPublicKey = musig2.keyAggExport(musig2.keyAggregate(this.cohort.cohortKeys));
771
783
  const nonces = musig2.nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
772
- this.secretNonce = nonces.secret;
784
+ this.#secretNonce = nonces.secret;
773
785
  return nonces.public;
774
786
  }
775
787
  /**
776
788
  * Generates a partial signature using the participant's secret key + secret nonce.
777
789
  * Requires the aggregated nonce to have been set first (via the service).
778
790
  *
779
- * Zeros the stored `secretNonce` after use. JS cannot truly erase memory (GC
780
- * and immutable strings), but overwriting the bytes shortens the exposure
781
- * window and prevents accidental reuse or serialization of a spent nonce.
791
+ * Clears the stored secret nonce after use on every path (success or throw)
792
+ * via {@link clearSecrets}. JS cannot truly erase memory (GC may relocate
793
+ * buffers), but overwriting the bytes shortens the exposure window and
794
+ * prevents accidental reuse or serialization of a spent nonce - reuse of a
795
+ * MuSig2 nonce leaks the secret key.
782
796
  */
783
797
  generatePartialSignature(participantSecretKey) {
784
798
  if (!this.aggregatedNonce) {
785
799
  throw new SigningSessionError("Aggregated nonce not available.", "MISSING_AGGREGATED_NONCE");
786
800
  }
787
- if (!this.secretNonce) {
801
+ if (!this.#secretNonce) {
788
802
  throw new SigningSessionError("Secret nonce not available \u2014 generateNonceContribution() must be called first.", "MISSING_SECRET_NONCE");
789
803
  }
790
804
  const session = new musig2.Session(
@@ -794,10 +808,23 @@ var BeaconSigningSession = class {
794
808
  [this.cohort.tapTweak],
795
809
  [true]
796
810
  );
797
- const partialSig = session.sign(this.secretNonce, participantSecretKey);
798
- this.secretNonce.fill(0);
799
- this.secretNonce = void 0;
800
- return partialSig;
811
+ try {
812
+ return session.sign(this.#secretNonce, participantSecretKey);
813
+ } finally {
814
+ this.clearSecrets();
815
+ }
816
+ }
817
+ /**
818
+ * Zeroize any retained secret nonce. Safe to call repeatedly and on any path
819
+ * (completion, failure, or teardown of an abandoned session). Callers that
820
+ * drop a session before it reaches a partial signature should invoke this so
821
+ * the secret nonce does not linger on the live object.
822
+ */
823
+ clearSecrets() {
824
+ if (this.#secretNonce) {
825
+ (0, import_keypair.wipe)(this.#secretNonce);
826
+ this.#secretNonce = void 0;
827
+ }
801
828
  }
802
829
  isComplete() {
803
830
  return this.phase === "Complete" /* Complete */;
@@ -811,13 +838,13 @@ var BeaconSigningSession = class {
811
838
  var DEFAULT_MAX_UPDATE_SIZE_BYTES = 256 * 1024;
812
839
  var AggregationService = class {
813
840
  did;
814
- keys;
841
+ publicKey;
815
842
  maxUpdateSizeBytes;
816
843
  /** Per-cohort state, keyed by cohortId. */
817
844
  #cohortStates = /* @__PURE__ */ new Map();
818
- constructor({ did, keys, maxUpdateSizeBytes }) {
845
+ constructor({ did, publicKey, maxUpdateSizeBytes }) {
819
846
  this.did = did;
820
- this.keys = keys;
847
+ this.publicKey = publicKey;
821
848
  this.maxUpdateSizeBytes = maxUpdateSizeBytes ?? DEFAULT_MAX_UPDATE_SIZE_BYTES;
822
849
  }
823
850
  receive(message) {
@@ -910,7 +937,7 @@ var AggregationService = class {
910
937
  cohortSize: state.config.minParticipants,
911
938
  beaconType: state.config.beaconType,
912
939
  network: state.config.network,
913
- communicationPk: this.keys.publicKey.compressed
940
+ communicationPk: this.publicKey.compressed
914
941
  });
915
942
  state.phase = "Advertised" /* Advertised */;
916
943
  return [message];
@@ -1322,12 +1349,17 @@ var import_utils3 = require("@noble/hashes/utils");
1322
1349
  var import_btc_signer3 = require("@scure/btc-signer");
1323
1350
  var AggregationParticipant = class {
1324
1351
  did;
1325
- keys;
1352
+ /** MuSig2 signing capability. The raw secret never lives as a field here. */
1353
+ #signer;
1326
1354
  /** Per-cohort state, keyed by cohortId. */
1327
1355
  #cohortStates = /* @__PURE__ */ new Map();
1328
- constructor({ did, keys }) {
1356
+ constructor({ did, signer }) {
1329
1357
  this.did = did;
1330
- this.keys = keys;
1358
+ this.#signer = signer;
1359
+ }
1360
+ /** The participant's compressed (33-byte) MuSig2 public key. Not secret. */
1361
+ get publicKey() {
1362
+ return this.#signer.publicKey;
1331
1363
  }
1332
1364
  /**
1333
1365
  * Process an incoming message. Updates internal state but never produces
@@ -1416,8 +1448,8 @@ var AggregationParticipant = class {
1416
1448
  from: this.did,
1417
1449
  to: state.serviceDid,
1418
1450
  cohortId,
1419
- participantPk: this.keys.publicKey.compressed,
1420
- communicationPk: this.keys.publicKey.compressed
1451
+ participantPk: this.publicKey,
1452
+ communicationPk: this.publicKey
1421
1453
  });
1422
1454
  return [optInMessage];
1423
1455
  }
@@ -1448,7 +1480,7 @@ var AggregationParticipant = class {
1448
1480
  const beaconAddress = message.body?.beaconAddress;
1449
1481
  const cohortKeys = message.body?.cohortKeys;
1450
1482
  if (!beaconAddress || !cohortKeys) return;
1451
- const participantPkHex = (0, import_utils3.bytesToHex)(this.keys.publicKey.compressed);
1483
+ const participantPkHex = (0, import_utils3.bytesToHex)(this.publicKey);
1452
1484
  const cohortKeysHex = cohortKeys.map((k) => (0, import_utils3.bytesToHex)(new Uint8Array(k)));
1453
1485
  state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
1454
1486
  state.phase = "CohortReady" /* CohortReady */;
@@ -1615,9 +1647,8 @@ var AggregationParticipant = class {
1615
1647
  prevOutValues
1616
1648
  });
1617
1649
  state.signingSession = session;
1618
- const nonceContribution = session.generateNonceContribution(
1619
- this.keys.publicKey.compressed,
1620
- this.keys.secretKey.bytes
1650
+ const nonceContribution = this.#signer.withSecret(
1651
+ (secretKey) => session.generateNonceContribution(this.publicKey, secretKey)
1621
1652
  );
1622
1653
  state.phase = "NonceSent" /* NonceSent */;
1623
1654
  return [createNonceContributionMessage({
@@ -1660,7 +1691,10 @@ var AggregationParticipant = class {
1660
1691
  { cohortId }
1661
1692
  );
1662
1693
  }
1663
- const partialSig = state.signingSession.generatePartialSignature(this.keys.secretKey.bytes);
1694
+ const signingSession = state.signingSession;
1695
+ const partialSig = this.#signer.withSecret(
1696
+ (secretKey) => signingSession.generatePartialSignature(secretKey)
1697
+ );
1664
1698
  state.phase = "Complete" /* Complete */;
1665
1699
  return [createSignatureAuthorizationMessage({
1666
1700
  from: this.did,
@@ -1673,6 +1707,37 @@ var AggregationParticipant = class {
1673
1707
  getCohortPhase(cohortId) {
1674
1708
  return this.#cohortStates.get(cohortId)?.phase;
1675
1709
  }
1710
+ /**
1711
+ * Zeroize any retained MuSig2 secret nonces across all cohorts. The raw
1712
+ * signing key is never held here (it lives behind the {@link AggregationSigner}
1713
+ * and is wiped per-operation), but an abandoned signing session can still hold
1714
+ * a secret nonce; call this on teardown to clear it deterministically.
1715
+ */
1716
+ clearSecrets() {
1717
+ for (const state of this.#cohortStates.values()) {
1718
+ state.signingSession?.clearSecrets();
1719
+ }
1720
+ }
1721
+ };
1722
+
1723
+ // src/core/aggregation/signer.ts
1724
+ var import_keypair2 = require("@did-btcr2/keypair");
1725
+ var KeyPairAggregationSigner = class {
1726
+ publicKey;
1727
+ #keys;
1728
+ /** @param {SchnorrKeyPair} keys The keypair whose secret backs this signer. */
1729
+ constructor(keys) {
1730
+ this.#keys = keys;
1731
+ this.publicKey = keys.publicKey.compressed;
1732
+ }
1733
+ withSecret(fn) {
1734
+ const secretKey = this.#keys.secretKey.bytes;
1735
+ try {
1736
+ return fn(secretKey);
1737
+ } finally {
1738
+ (0, import_keypair2.wipe)(secretKey);
1739
+ }
1740
+ }
1676
1741
  };
1677
1742
 
1678
1743
  // src/core/aggregation/logger.ts
@@ -1784,11 +1849,11 @@ var TransportAdapterError = class extends import_common6.MethodError {
1784
1849
  var import_common10 = require("@did-btcr2/common");
1785
1850
 
1786
1851
  // src/core/aggregation/transport/http/client.ts
1787
- var import_keypair2 = require("@did-btcr2/keypair");
1852
+ var import_keypair4 = require("@did-btcr2/keypair");
1788
1853
 
1789
1854
  // src/core/identifier.ts
1790
1855
  var import_common7 = require("@did-btcr2/common");
1791
- var import_keypair = require("@did-btcr2/keypair");
1856
+ var import_keypair3 = require("@did-btcr2/keypair");
1792
1857
  var import_base4 = require("@scure/base");
1793
1858
  var Identifier = class _Identifier {
1794
1859
  /**
@@ -1821,7 +1886,7 @@ var Identifier = class _Identifier {
1821
1886
  }
1822
1887
  if (idType === "KEY") {
1823
1888
  try {
1824
- new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
1889
+ new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1825
1890
  } catch {
1826
1891
  throw new import_common7.IdentifierError(
1827
1892
  'Expected "genesisBytes" to be a valid compressed secp256k1 public key',
@@ -1923,7 +1988,7 @@ var Identifier = class _Identifier {
1923
1988
  const genesisBytes = dataBytes.slice(byteIndex + 1);
1924
1989
  if (idType === "KEY") {
1925
1990
  try {
1926
- new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
1991
+ new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1927
1992
  } catch {
1928
1993
  throw new import_common7.IdentifierError(`Invalid genesisBytes: ${genesisBytes}`, import_common7.INVALID_DID, { identifier });
1929
1994
  }
@@ -1935,7 +2000,7 @@ var Identifier = class _Identifier {
1935
2000
  * @returns {string} The new did:btcr2 identifier.
1936
2001
  */
1937
2002
  static generate() {
1938
- const keyPair = import_keypair.SchnorrKeyPair.generate();
2003
+ const keyPair = import_keypair3.SchnorrKeyPair.generate();
1939
2004
  const did = this.encode(
1940
2005
  keyPair.publicKey.compressed,
1941
2006
  {
@@ -1961,7 +2026,7 @@ var Identifier = class _Identifier {
1961
2026
  { did, idType }
1962
2027
  );
1963
2028
  }
1964
- return new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
2029
+ return new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1965
2030
  }
1966
2031
  /**
1967
2032
  * Validates a did:btcr2 identifier.
@@ -2368,7 +2433,7 @@ var HttpClientTransport = class {
2368
2433
  }
2369
2434
  registerPeer(did, communicationPk) {
2370
2435
  try {
2371
- new import_keypair2.CompressedSecp256k1PublicKey(communicationPk);
2436
+ new import_keypair4.CompressedSecp256k1PublicKey(communicationPk);
2372
2437
  } catch {
2373
2438
  throw new HttpTransportError(
2374
2439
  `Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
@@ -2564,14 +2629,14 @@ var HttpClientTransport = class {
2564
2629
  const peerBytes = this.#peers.get(did);
2565
2630
  if (peerBytes) {
2566
2631
  try {
2567
- return new import_keypair2.CompressedSecp256k1PublicKey(peerBytes);
2632
+ return new import_keypair4.CompressedSecp256k1PublicKey(peerBytes);
2568
2633
  } catch {
2569
2634
  }
2570
2635
  }
2571
2636
  try {
2572
2637
  const components = Identifier.decode(did);
2573
2638
  if (components.idType === "KEY") {
2574
- return new import_keypair2.CompressedSecp256k1PublicKey(components.genesisBytes);
2639
+ return new import_keypair4.CompressedSecp256k1PublicKey(components.genesisBytes);
2575
2640
  }
2576
2641
  } catch {
2577
2642
  }
@@ -2616,7 +2681,7 @@ function flattenMessage(msg) {
2616
2681
  }
2617
2682
 
2618
2683
  // src/core/aggregation/transport/http/server.ts
2619
- var import_keypair3 = require("@did-btcr2/keypair");
2684
+ var import_keypair5 = require("@did-btcr2/keypair");
2620
2685
 
2621
2686
  // src/core/aggregation/transport/http/inbox-buffer.ts
2622
2687
  var InboxBuffer = class {
@@ -2781,7 +2846,7 @@ var HttpServerTransport = class {
2781
2846
  }
2782
2847
  registerPeer(did, communicationPk) {
2783
2848
  try {
2784
- new import_keypair3.CompressedSecp256k1PublicKey(communicationPk);
2849
+ new import_keypair5.CompressedSecp256k1PublicKey(communicationPk);
2785
2850
  } catch {
2786
2851
  throw new HttpTransportError(
2787
2852
  `Invalid peer public key for ${did}`,
@@ -3059,14 +3124,14 @@ var HttpServerTransport = class {
3059
3124
  const peerBytes = this.#peers.get(did);
3060
3125
  if (peerBytes) {
3061
3126
  try {
3062
- return new import_keypair3.CompressedSecp256k1PublicKey(peerBytes);
3127
+ return new import_keypair5.CompressedSecp256k1PublicKey(peerBytes);
3063
3128
  } catch {
3064
3129
  }
3065
3130
  }
3066
3131
  try {
3067
3132
  const components = Identifier.decode(did);
3068
3133
  if (components.idType === "KEY") {
3069
- return new import_keypair3.CompressedSecp256k1PublicKey(components.genesisBytes);
3134
+ return new import_keypair5.CompressedSecp256k1PublicKey(components.genesisBytes);
3070
3135
  }
3071
3136
  } catch {
3072
3137
  }
@@ -3165,7 +3230,7 @@ function flattenMessage2(msg) {
3165
3230
  }
3166
3231
 
3167
3232
  // src/core/aggregation/transport/nostr.ts
3168
- var import_keypair4 = require("@did-btcr2/keypair");
3233
+ var import_keypair6 = require("@did-btcr2/keypair");
3169
3234
  var import_utils6 = require("@noble/hashes/utils");
3170
3235
  var import_nostr_tools = require("nostr-tools");
3171
3236
  var import_pool = require("nostr-tools/pool");
@@ -3263,7 +3328,7 @@ var NostrTransport = class _NostrTransport {
3263
3328
  */
3264
3329
  registerPeer(did, communicationPk) {
3265
3330
  try {
3266
- new import_keypair4.CompressedSecp256k1PublicKey(communicationPk);
3331
+ new import_keypair6.CompressedSecp256k1PublicKey(communicationPk);
3267
3332
  } catch {
3268
3333
  throw new TransportAdapterError(
3269
3334
  `Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
@@ -3370,7 +3435,7 @@ var NostrTransport = class _NostrTransport {
3370
3435
  if (to) {
3371
3436
  const recipientPkBytes = this.#peerRegistry.get(to);
3372
3437
  if (recipientPkBytes) {
3373
- const recipientPk = new import_keypair4.CompressedSecp256k1PublicKey(recipientPkBytes);
3438
+ const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
3374
3439
  tags.push(["p", (0, import_utils6.bytesToHex)(recipientPk.x)]);
3375
3440
  }
3376
3441
  }
@@ -3401,7 +3466,7 @@ var NostrTransport = class _NostrTransport {
3401
3466
  { adapter: this.name, did: to }
3402
3467
  );
3403
3468
  }
3404
- const recipientPk = new import_keypair4.CompressedSecp256k1PublicKey(recipientPkBytes);
3469
+ const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
3405
3470
  const conversationKey = import_nostr_tools.nip44.v2.utils.getConversationKey(
3406
3471
  senderKeys.secretKey.bytes,
3407
3472
  (0, import_utils6.bytesToHex)(recipientPk.x)
@@ -3641,6 +3706,119 @@ var TransportFactory = class {
3641
3706
  }
3642
3707
  };
3643
3708
 
3709
+ // src/core/aggregation/transport/in-memory.ts
3710
+ var import_utils7 = require("@noble/hashes/utils");
3711
+ var InMemoryBus = class {
3712
+ #transports = /* @__PURE__ */ new Set();
3713
+ /** Attach a transport to this bus. Called by the transport's constructor. */
3714
+ register(transport) {
3715
+ this.#transports.add(transport);
3716
+ }
3717
+ /** Detach a transport from this bus. */
3718
+ unregister(transport) {
3719
+ this.#transports.delete(transport);
3720
+ }
3721
+ /**
3722
+ * Deliver a message. With no `recipient` the message is broadcast to every
3723
+ * actor on the bus; otherwise it is routed to the single transport that owns
3724
+ * the recipient DID.
3725
+ */
3726
+ async deliver(message, _sender, recipient) {
3727
+ const type = message.type;
3728
+ if (!type) return;
3729
+ const replacer = (_k, v) => v instanceof Uint8Array ? { __bytes: (0, import_utils7.bytesToHex)(v) } : v;
3730
+ const reviver = (_k, v) => v && typeof v === "object" && "__bytes" in v ? (0, import_utils7.hexToBytes)(v.__bytes) : v;
3731
+ const raw = JSON.parse(JSON.stringify(message, replacer), reviver);
3732
+ const serialized = { ...raw, ...raw.body ?? {} };
3733
+ if (!recipient) {
3734
+ for (const t of this.#transports) {
3735
+ await t.dispatchBroadcast(type, serialized);
3736
+ }
3737
+ return;
3738
+ }
3739
+ for (const t of this.#transports) {
3740
+ if (t.hasActor(recipient)) {
3741
+ await t.dispatchDirected(recipient, type, serialized);
3742
+ return;
3743
+ }
3744
+ }
3745
+ }
3746
+ };
3747
+ var InMemoryTransport = class {
3748
+ name = "in-memory";
3749
+ bus;
3750
+ #actors = /* @__PURE__ */ new Map();
3751
+ #peers = /* @__PURE__ */ new Map();
3752
+ /** @param bus Shared bus. Pass the same bus to connect multiple transports. */
3753
+ constructor(bus = new InMemoryBus()) {
3754
+ this.bus = bus;
3755
+ this.bus.register(this);
3756
+ }
3757
+ start() {
3758
+ }
3759
+ registerActor(did, keys) {
3760
+ this.#actors.set(did, { publicKey: keys.publicKey.compressed, handlers: /* @__PURE__ */ new Map() });
3761
+ }
3762
+ getActorPk(did) {
3763
+ return this.#actors.get(did)?.publicKey;
3764
+ }
3765
+ /** True if `did` is registered on this transport. Used by the bus for routing. */
3766
+ hasActor(did) {
3767
+ return this.#actors.has(did);
3768
+ }
3769
+ registerPeer(did, communicationPk) {
3770
+ this.#peers.set(did, communicationPk);
3771
+ }
3772
+ getPeerPk(did) {
3773
+ return this.#peers.get(did);
3774
+ }
3775
+ registerMessageHandler(actorDid, messageType, handler) {
3776
+ const actor = this.#actors.get(actorDid);
3777
+ if (actor) actor.handlers.set(messageType, handler);
3778
+ }
3779
+ unregisterMessageHandler(actorDid, messageType) {
3780
+ const actor = this.#actors.get(actorDid);
3781
+ if (actor) actor.handlers.delete(messageType);
3782
+ }
3783
+ unregisterActor(did) {
3784
+ const actor = this.#actors.get(did);
3785
+ if (!actor) return;
3786
+ actor.handlers.clear();
3787
+ this.#actors.delete(did);
3788
+ this.#peers.delete(did);
3789
+ }
3790
+ async sendMessage(message, sender, recipient) {
3791
+ await this.bus.deliver(message, sender, recipient);
3792
+ }
3793
+ publishRepeating(message, sender, intervalMs, recipient) {
3794
+ let stopped = false;
3795
+ void this.sendMessage(message, sender, recipient).catch(() => {
3796
+ });
3797
+ const timer = setInterval(() => {
3798
+ if (stopped) return;
3799
+ void this.sendMessage(message, sender, recipient).catch(() => {
3800
+ });
3801
+ }, intervalMs);
3802
+ return () => {
3803
+ if (stopped) return;
3804
+ stopped = true;
3805
+ clearInterval(timer);
3806
+ };
3807
+ }
3808
+ /** Deliver a broadcast message to every actor on this transport that handles `type`. */
3809
+ async dispatchBroadcast(type, message) {
3810
+ for (const actor of this.#actors.values()) {
3811
+ const handler = actor.handlers.get(type);
3812
+ if (handler) await handler(message);
3813
+ }
3814
+ }
3815
+ /** Deliver a directed message to the recipient actor's handler for `type`. */
3816
+ async dispatchDirected(recipientDid, type, message) {
3817
+ const handler = this.#actors.get(recipientDid)?.handlers.get(type);
3818
+ if (handler) await handler(message);
3819
+ }
3820
+ };
3821
+
3644
3822
  // src/core/aggregation/transport/didcomm.ts
3645
3823
  var import_common11 = require("@did-btcr2/common");
3646
3824
  var DidCommTransport = class {
@@ -3793,8 +3971,11 @@ var AggregationServiceRunner = class _AggregationServiceRunner extends TypedEven
3793
3971
  this.#phaseTimeoutMs = options.phaseTimeoutMs;
3794
3972
  this.#advertRepeatIntervalMs = options.advertRepeatIntervalMs ?? DEFAULT_ADVERT_REPEAT_INTERVAL_MS;
3795
3973
  this.session = new AggregationService({
3974
+ // The coordinator never signs, so the state machine receives only the
3975
+ // public half of the operator's keypair (see ADR 038). The full keypair
3976
+ // remains the operator's transport/communication identity.
3796
3977
  did: options.did,
3797
- keys: options.keys,
3978
+ publicKey: options.keys.publicKey,
3798
3979
  maxUpdateSizeBytes: options.maxUpdateSizeBytes
3799
3980
  });
3800
3981
  }
@@ -4146,7 +4327,10 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
4146
4327
  this.#onProvideUpdate = options.onProvideUpdate;
4147
4328
  this.#onValidateData = options.onValidateData ?? (async (info) => ({ approved: info.matches }));
4148
4329
  this.#onApproveSigning = options.onApproveSigning ?? (async () => ({ approved: true }));
4149
- this.session = new AggregationParticipant({ did: options.did, keys: options.keys });
4330
+ this.session = new AggregationParticipant({
4331
+ did: options.did,
4332
+ signer: new KeyPairAggregationSigner(options.keys)
4333
+ });
4150
4334
  }
4151
4335
  /**
4152
4336
  * Start listening for cohorts. The runner stays active until {@link stop}
@@ -4159,6 +4343,7 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
4159
4343
  stop() {
4160
4344
  this.#stopped = true;
4161
4345
  this.#unregisterHandlers();
4346
+ this.session.clearSecrets();
4162
4347
  }
4163
4348
  /** Message types this runner listens for on the transport. */
4164
4349
  static #HANDLED_MESSAGE_TYPES = [
@@ -4368,8 +4553,64 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
4368
4553
  }
4369
4554
  };
4370
4555
 
4556
+ // src/core/aggregation/runner/aggregation-runner.ts
4557
+ var AggregationRunner = class {
4558
+ /**
4559
+ * Run a cohort of ONE participant entirely in-process and return the
4560
+ * aggregated MuSig2 result.
4561
+ *
4562
+ * One party plays both the coordinating service and the lone participant,
4563
+ * connected over an {@link InMemoryTransport} (no relay or HTTP server). This
4564
+ * makes the single-participant aggregate-beacon path — the N=1 corner of the
4565
+ * two-axis beacon matrix (see ADR 037) — first-class, useful for generating
4566
+ * and reproducing single-participant aggregate test vectors.
4567
+ *
4568
+ * The service advertises a cohort with `minParticipants: 1`; the participant
4569
+ * joins, submits its update, and the two complete keygen, data distribution,
4570
+ * validation, and a one-signer MuSig2 P2TR key-path signing round.
4571
+ *
4572
+ * @param options Service + participant identities, cohort config, and the
4573
+ * update / tx-data callbacks.
4574
+ * @returns The {@link AggregationResult} (cohort id, aggregated signature, signed tx).
4575
+ */
4576
+ static async solo(options) {
4577
+ const transport = new InMemoryTransport(new InMemoryBus());
4578
+ transport.registerActor(options.service.did, options.service.keys);
4579
+ transport.registerActor(options.participant.did, options.participant.keys);
4580
+ transport.registerPeer(options.participant.did, options.participant.keys.publicKey.compressed);
4581
+ transport.registerPeer(options.service.did, options.service.keys.publicKey.compressed);
4582
+ transport.start();
4583
+ const service = new AggregationServiceRunner({
4584
+ transport,
4585
+ did: options.service.did,
4586
+ keys: options.service.keys,
4587
+ config: { minParticipants: 1, network: options.config.network, beaconType: options.config.beaconType },
4588
+ onProvideTxData: options.onProvideTxData,
4589
+ cohortTtlMs: options.cohortTtlMs,
4590
+ phaseTimeoutMs: options.phaseTimeoutMs,
4591
+ // In-process bus with the participant already listening: a single advert
4592
+ // suffices, so disable the republish loop (no dangling interval).
4593
+ advertRepeatIntervalMs: 0
4594
+ });
4595
+ const participant = new AggregationParticipantRunner({
4596
+ transport,
4597
+ did: options.participant.did,
4598
+ keys: options.participant.keys,
4599
+ shouldJoin: async () => true,
4600
+ onProvideUpdate: options.onProvideUpdate
4601
+ });
4602
+ await participant.start();
4603
+ try {
4604
+ return await service.run();
4605
+ } finally {
4606
+ participant.stop();
4607
+ service.stop();
4608
+ }
4609
+ }
4610
+ };
4611
+
4371
4612
  // src/core/beacon/beacon.ts
4372
- var import_utils7 = require("@noble/hashes/utils.js");
4613
+ var import_utils8 = require("@noble/hashes/utils.js");
4373
4614
  var import_btc_signer4 = require("@scure/btc-signer");
4374
4615
 
4375
4616
  // src/core/beacon/error.ts
@@ -4467,7 +4708,7 @@ async function fetchSpendableUtxo(bitcoinAddress, bitcoin) {
4467
4708
  );
4468
4709
  }
4469
4710
  const prevTxHex = await bitcoin.rest.transaction.getHex(utxo.txid);
4470
- return { utxo, prevTxBytes: (0, import_utils7.hexToBytes)(prevTxHex) };
4711
+ return { utxo, prevTxBytes: (0, import_utils8.hexToBytes)(prevTxHex) };
4471
4712
  }
4472
4713
  async function buildAggregationBeaconTx(opts) {
4473
4714
  const feeEstimator = opts.feeEstimator ?? DEFAULT_FEE_ESTIMATOR;
@@ -4508,7 +4749,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
4508
4749
  const sighashType = import_btc_signer4.SigHash.ALL;
4509
4750
  const sighash2 = tx.preimageLegacy(inputIdx, prevOutScript, sighashType);
4510
4751
  const sig2 = signer.sign(sighash2, "ecdsa");
4511
- const sigWithType = (0, import_utils7.concatBytes)(sig2, new Uint8Array([sighashType]));
4752
+ const sigWithType = (0, import_utils8.concatBytes)(sig2, new Uint8Array([sighashType]));
4512
4753
  tx.updateInput(inputIdx, { partialSig: [[pubkey, sigWithType]] }, true);
4513
4754
  tx.finalize();
4514
4755
  return tx.hex;
@@ -4526,7 +4767,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
4526
4767
  const sighashType = import_btc_signer4.SigHash.ALL;
4527
4768
  const sighash2 = tx.preimageWitnessV0(inputIdx, sighashScript, sighashType, amount);
4528
4769
  const sig2 = signer.sign(sighash2, "ecdsa");
4529
- const sigWithType = (0, import_utils7.concatBytes)(sig2, new Uint8Array([sighashType]));
4770
+ const sigWithType = (0, import_utils8.concatBytes)(sig2, new Uint8Array([sighashType]));
4530
4771
  tx.updateInput(inputIdx, { partialSig: [[pubkey, sigWithType]] }, true);
4531
4772
  tx.finalize();
4532
4773
  return tx.hex;
@@ -4537,7 +4778,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
4537
4778
  tx.finalize();
4538
4779
  return tx.hex;
4539
4780
  }
4540
- var Beacon = class {
4781
+ var SinglePartyBeacon = class {
4541
4782
  /**
4542
4783
  * The Beacon service configuration parsed from the DID Document.
4543
4784
  */
@@ -4674,7 +4915,7 @@ var Beacon = class {
4674
4915
 
4675
4916
  // src/core/beacon/cas-beacon.ts
4676
4917
  var import_common13 = require("@did-btcr2/common");
4677
- var CASBeacon = class extends Beacon {
4918
+ var CASBeacon = class extends SinglePartyBeacon {
4678
4919
  /**
4679
4920
  * Creates an instance of CASBeacon.
4680
4921
  * @param {BeaconService} service The service of the Beacon.
@@ -4734,7 +4975,7 @@ var CASBeacon = class extends Beacon {
4734
4975
  * Creates a CAS Announcement mapping the DID to the update hash, broadcasts the hash of the
4735
4976
  * announcement via OP_RETURN, and optionally publishes the announcement off-chain via the
4736
4977
  * supplied `casPublish` callback. UTXO selection, PSBT construction, fee estimation, signing,
4737
- * and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
4978
+ * and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
4738
4979
  *
4739
4980
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
4740
4981
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -4762,7 +5003,7 @@ var import_common16 = require("@did-btcr2/common");
4762
5003
 
4763
5004
  // src/core/beacon/singleton-beacon.ts
4764
5005
  var import_common14 = require("@did-btcr2/common");
4765
- var SingletonBeacon = class extends Beacon {
5006
+ var SingletonBeacon = class extends SinglePartyBeacon {
4766
5007
  /**
4767
5008
  * Creates an instance of SingletonBeacon.
4768
5009
  * @param {BeaconService} service The BeaconService object representing the funded beacon to announce the update to.
@@ -4799,7 +5040,7 @@ var SingletonBeacon = class extends Beacon {
4799
5040
  *
4800
5041
  * The signal bytes embedded in OP_RETURN are the SHA-256 canonical hash of the signed update.
4801
5042
  * UTXO selection, PSBT construction, fee estimation, signing, and broadcast are delegated to
4802
- * {@link Beacon.buildSignAndBroadcast}.
5043
+ * {@link SinglePartyBeacon.buildSignAndBroadcast}.
4803
5044
  *
4804
5045
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
4805
5046
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -4818,8 +5059,8 @@ var SingletonBeacon = class extends Beacon {
4818
5059
  // src/core/beacon/smt-beacon.ts
4819
5060
  var import_common15 = require("@did-btcr2/common");
4820
5061
  var import_smt3 = require("@did-btcr2/smt");
4821
- var import_utils8 = require("@noble/hashes/utils");
4822
- var SMTBeacon = class extends Beacon {
5062
+ var import_utils9 = require("@noble/hashes/utils");
5063
+ var SMTBeacon = class extends SinglePartyBeacon {
4823
5064
  /**
4824
5065
  * Creates an instance of SMTBeacon.
4825
5066
  * @param {BeaconService} service The Beacon service.
@@ -4895,7 +5136,7 @@ var SMTBeacon = class extends Beacon {
4895
5136
  * Builds a single-entry Sparse Merkle Tree from the signed update, then broadcasts the tree's
4896
5137
  * root hash via OP_RETURN. For multi-party aggregation, use the {@link AggregationService}
4897
5138
  * subsystem directly instead of this method. UTXO selection, PSBT construction, fee estimation,
4898
- * signing, and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
5139
+ * signing, and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
4899
5140
  *
4900
5141
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
4901
5142
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -4907,7 +5148,7 @@ var SMTBeacon = class extends Beacon {
4907
5148
  async broadcastSignal(signedUpdate, signer, bitcoin, options) {
4908
5149
  const did = this.service.id.split("#")[0];
4909
5150
  const canonicalBytes = new TextEncoder().encode((0, import_common15.canonicalize)(signedUpdate));
4910
- const nonce = (0, import_utils8.randomBytes)(32);
5151
+ const nonce = (0, import_utils9.randomBytes)(32);
4911
5152
  const tree = new import_smt3.BTCR2MerkleTree();
4912
5153
  tree.addEntries([{ did, nonce, signedUpdate: canonicalBytes }]);
4913
5154
  tree.finalize();
@@ -4921,7 +5162,7 @@ var BeaconFactory = class {
4921
5162
  /**
4922
5163
  * Establish a Beacon instance based on the provided service and optional sidecar data.
4923
5164
  * @param {BeaconService} service The beacon service configuration.
4924
- * @returns {Beacon} The established Beacon instance.
5165
+ * @returns {SinglePartyBeacon} The established Beacon instance.
4925
5166
  */
4926
5167
  static establish(service) {
4927
5168
  switch (service.type) {
@@ -4938,11 +5179,11 @@ var BeaconFactory = class {
4938
5179
  };
4939
5180
 
4940
5181
  // src/core/beacon/signal-discovery.ts
4941
- var import_bitcoin2 = require("@did-btcr2/bitcoin");
5182
+ var import_bitcoin3 = require("@did-btcr2/bitcoin");
4942
5183
  var import_common18 = require("@did-btcr2/common");
4943
5184
 
4944
5185
  // src/core/beacon/utils.ts
4945
- var import_bitcoin = require("@did-btcr2/bitcoin");
5186
+ var import_bitcoin2 = require("@did-btcr2/bitcoin");
4946
5187
  var import_common17 = require("@did-btcr2/common");
4947
5188
  var import_btc_signer5 = require("@scure/btc-signer");
4948
5189
 
@@ -6049,7 +6290,7 @@ var BeaconUtils = class {
6049
6290
  static createBeaconService(did, addressType, beaconType) {
6050
6291
  try {
6051
6292
  const components = Identifier.decode(did);
6052
- const network = (0, import_bitcoin.getNetwork)(components.network);
6293
+ const network = (0, import_bitcoin2.getNetwork)(components.network);
6053
6294
  const pubkey = components.genesisBytes;
6054
6295
  const id = `${did}#initial${addressType.toUpperCase()}`;
6055
6296
  const address = addressType === "p2tr" ? (0, import_btc_signer5.p2tr)(pubkey.slice(1, 33), void 0, network).address : addressType === "p2wpkh" ? (0, import_btc_signer5.p2wpkh)(pubkey, network).address : (0, import_btc_signer5.p2pkh)(pubkey, network).address;
@@ -6200,14 +6441,14 @@ var BeaconSignalDiscovery = class {
6200
6441
  console.info(`Searching for beacon signals, please wait ...`);
6201
6442
  while (block.height <= targetHeight) {
6202
6443
  for (const tx of block.tx) {
6203
- if (tx.txid === import_bitcoin2.GENESIS_TX_ID) {
6444
+ if (tx.txid === import_bitcoin3.GENESIS_TX_ID) {
6204
6445
  continue;
6205
6446
  }
6206
6447
  for (const vin of tx.vin) {
6207
6448
  if (vin.coinbase) {
6208
6449
  continue;
6209
6450
  }
6210
- if (vin.txinwitness && vin.txinwitness.length === 1 && vin.txinwitness[0] === import_bitcoin2.TXIN_WITNESS_COINBASE) {
6451
+ if (vin.txinwitness && vin.txinwitness.length === 1 && vin.txinwitness[0] === import_bitcoin3.TXIN_WITNESS_COINBASE) {
6211
6452
  continue;
6212
6453
  }
6213
6454
  if (!vin.txid) {
@@ -6261,10 +6502,10 @@ var BeaconSignalDiscovery = class {
6261
6502
  };
6262
6503
 
6263
6504
  // src/core/resolver.ts
6264
- var import_bitcoin4 = require("@did-btcr2/bitcoin");
6505
+ var import_bitcoin5 = require("@did-btcr2/bitcoin");
6265
6506
  var import_common22 = require("@did-btcr2/common");
6266
6507
  var import_cryptosuite3 = require("@did-btcr2/cryptosuite");
6267
- var import_keypair6 = require("@did-btcr2/keypair");
6508
+ var import_keypair8 = require("@did-btcr2/keypair");
6268
6509
 
6269
6510
  // src/did-btcr2.ts
6270
6511
  var import_common21 = require("@did-btcr2/common");
@@ -6275,10 +6516,10 @@ var import_common20 = require("@did-btcr2/common");
6275
6516
  var import_cryptosuite2 = require("@did-btcr2/cryptosuite");
6276
6517
 
6277
6518
  // src/utils/did-document.ts
6278
- var import_bitcoin3 = require("@did-btcr2/bitcoin");
6519
+ var import_bitcoin4 = require("@did-btcr2/bitcoin");
6279
6520
  var import_common19 = require("@did-btcr2/common");
6280
- var import_keypair5 = require("@did-btcr2/keypair");
6281
- var import_utils10 = require("@web5/dids/utils");
6521
+ var import_keypair7 = require("@did-btcr2/keypair");
6522
+ var import_utils11 = require("@web5/dids/utils");
6282
6523
  var import_btc_signer6 = require("@scure/btc-signer");
6283
6524
  var BTCR2_DID_DOCUMENT_CONTEXT = [
6284
6525
  "https://www.w3.org/ns/did/v1.1",
@@ -6488,7 +6729,7 @@ var DidDocument = class _DidDocument {
6488
6729
  * @returns {boolean} True if the services are valid.
6489
6730
  */
6490
6731
  static isValidServices(service) {
6491
- return Array.isArray(service) && service.every(import_utils10.isDidService);
6732
+ return Array.isArray(service) && service.every(import_utils11.isDidService);
6492
6733
  }
6493
6734
  /**
6494
6735
  * Validates verification relationships (authentication, assertionMethod, capabilityInvocation, capabilityDelegation).
@@ -6599,9 +6840,9 @@ var GenesisDocument = class _GenesisDocument extends DidDocument {
6599
6840
  * @returns {GenesisDocument} A new GenesisDocument with the placeholder ID.
6600
6841
  */
6601
6842
  static fromPublicKey(publicKey, network) {
6602
- const pk = new import_keypair5.CompressedSecp256k1PublicKey(publicKey);
6843
+ const pk = new import_keypair7.CompressedSecp256k1PublicKey(publicKey);
6603
6844
  const id = ID_PLACEHOLDER_VALUE;
6604
- const address = (0, import_btc_signer6.p2pkh)(pk.compressed, (0, import_bitcoin3.getNetwork)(network)).address;
6845
+ const address = (0, import_btc_signer6.p2pkh)(pk.compressed, (0, import_bitcoin4.getNetwork)(network)).address;
6605
6846
  const services = [{
6606
6847
  id: `${id}#service-0`,
6607
6848
  serviceEndpoint: `bitcoin:${address}`,
@@ -7068,7 +7309,7 @@ var DidBtcr2 = class {
7068
7309
  };
7069
7310
 
7070
7311
  // src/core/resolver.ts
7071
- var import_utils12 = require("@noble/curves/utils.js");
7312
+ var import_utils13 = require("@noble/curves/utils.js");
7072
7313
  var Resolver = class _Resolver {
7073
7314
  // --- Immutable inputs ---
7074
7315
  #didComponents;
@@ -7108,11 +7349,11 @@ var Resolver = class _Resolver {
7108
7349
  static deterministic(didComponents) {
7109
7350
  const genesisBytes = didComponents.genesisBytes;
7110
7351
  const did = Identifier.encode(genesisBytes, didComponents);
7111
- const { multibase } = new import_keypair6.CompressedSecp256k1PublicKey(genesisBytes);
7352
+ const { multibase } = new import_keypair8.CompressedSecp256k1PublicKey(genesisBytes);
7112
7353
  const service = BeaconUtils.generateBeaconServices({
7113
7354
  id: did,
7114
7355
  publicKey: genesisBytes,
7115
- network: (0, import_bitcoin4.getNetwork)(didComponents.network),
7356
+ network: (0, import_bitcoin5.getNetwork)(didComponents.network),
7116
7357
  beaconType: "SingletonBeacon"
7117
7358
  });
7118
7359
  return new DidDocument({
@@ -7135,7 +7376,7 @@ var Resolver = class _Resolver {
7135
7376
  */
7136
7377
  static external(didComponents, genesisDocument) {
7137
7378
  const genesisDocumentHash = (0, import_common22.canonicalHashBytes)(genesisDocument);
7138
- if (!(0, import_utils12.equalBytes)(didComponents.genesisBytes, genesisDocumentHash)) {
7379
+ if (!(0, import_utils13.equalBytes)(didComponents.genesisBytes, genesisDocumentHash)) {
7139
7380
  throw new import_common22.ResolveError(
7140
7381
  `Initial document mismatch: genesisBytes !== genesisDocumentHash`,
7141
7382
  import_common22.INVALID_DID_DOCUMENT,
@@ -7212,7 +7453,7 @@ var Resolver = class _Resolver {
7212
7453
  this.confirmDuplicate(update, updateHashHistory);
7213
7454
  } else if (update.targetVersionId === currentVersionId + 1) {
7214
7455
  const sourceHashBytes = (0, import_common22.decode)(update.sourceHash, "base64urlnopad");
7215
- if (!(0, import_utils12.equalBytes)(sourceHashBytes, currentDocumentHash)) {
7456
+ if (!(0, import_utils13.equalBytes)(sourceHashBytes, currentDocumentHash)) {
7216
7457
  throw new import_common22.ResolveError(
7217
7458
  `Hash mismatch: update.sourceHash !== currentDocumentHash`,
7218
7459
  import_common22.INVALID_DID_UPDATE,
@@ -7259,7 +7500,7 @@ var Resolver = class _Resolver {
7259
7500
  const { proof: _, ...unsignedUpdate } = update;
7260
7501
  const unsignedUpdateHash = (0, import_common22.canonicalHashBytes)(unsignedUpdate);
7261
7502
  const historicalUpdateHash = updateHashHistory[update.targetVersionId - 2];
7262
- if (!(0, import_utils12.equalBytes)(historicalUpdateHash, unsignedUpdateHash)) {
7503
+ if (!(0, import_utils13.equalBytes)(historicalUpdateHash, unsignedUpdateHash)) {
7263
7504
  throw new import_common22.ResolveError(
7264
7505
  `Invalid duplicate: unsigned update hash does not match historical hash`,
7265
7506
  import_common22.LATE_PUBLISHING_ERROR,
@@ -7312,7 +7553,7 @@ var Resolver = class _Resolver {
7312
7553
  DidDocument.validate(updatedDocument);
7313
7554
  const currentDocumentHash = (0, import_common22.canonicalHashBytes)(updatedDocument);
7314
7555
  const updateTargetHash = (0, import_common22.decode)(update.targetHash);
7315
- if (!(0, import_utils12.equalBytes)(updateTargetHash, currentDocumentHash)) {
7556
+ if (!(0, import_utils13.equalBytes)(updateTargetHash, currentDocumentHash)) {
7316
7557
  throw new import_common22.ResolveError(
7317
7558
  `Invalid update: update.targetHash !== currentDocumentHash`,
7318
7559
  import_common22.INVALID_DID_UPDATE,
@@ -7539,6 +7780,7 @@ var DidDocumentBuilder = class {
7539
7780
  AggregationParticipant,
7540
7781
  AggregationParticipantError,
7541
7782
  AggregationParticipantRunner,
7783
+ AggregationRunner,
7542
7784
  AggregationService,
7543
7785
  AggregationServiceError,
7544
7786
  AggregationServiceRunner,
@@ -7546,7 +7788,6 @@ var DidDocumentBuilder = class {
7546
7788
  BECH32M_CHARS,
7547
7789
  BTCR2_DID_DOCUMENT_CONTEXT,
7548
7790
  BaseMessage,
7549
- Beacon,
7550
7791
  BeaconError,
7551
7792
  BeaconFactory,
7552
7793
  BeaconSignalDiscovery,
@@ -7581,8 +7822,11 @@ var DidDocumentBuilder = class {
7581
7822
  HttpTransportError,
7582
7823
  ID_PLACEHOLDER_VALUE,
7583
7824
  Identifier,
7825
+ InMemoryBus,
7584
7826
  InMemoryRateLimitStore,
7827
+ InMemoryTransport,
7585
7828
  InboxBuffer,
7829
+ KeyPairAggregationSigner,
7586
7830
  NONCE_CONTRIBUTION,
7587
7831
  NonceCache,
7588
7832
  NostrTransport,
@@ -7603,6 +7847,7 @@ var DidDocumentBuilder = class {
7603
7847
  ServiceCohortPhase,
7604
7848
  SigningSessionError,
7605
7849
  SigningSessionPhase,
7850
+ SinglePartyBeacon,
7606
7851
  SingletonBeacon,
7607
7852
  SingletonBeaconError,
7608
7853
  StaticFeeEstimator,