@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/browser.mjs CHANGED
@@ -99982,6 +99982,13 @@ function compareBytes(a2, b) {
99982
99982
  // ../keypair/dist/esm/types.js
99983
99983
  init_shim();
99984
99984
 
99985
+ // ../keypair/dist/esm/utils.js
99986
+ init_shim();
99987
+ function wipe(bytes3) {
99988
+ if (bytes3)
99989
+ bytes3.fill(0);
99990
+ }
99991
+
99985
99992
  // ../cryptosuite/dist/esm/multikey/index.js
99986
99993
  init_secp256k1();
99987
99994
  init_utils();
@@ -100568,8 +100575,48 @@ function getBeaconStrategy(type) {
100568
100575
 
100569
100576
  // src/core/aggregation/cohort.ts
100570
100577
  init_shim();
100571
- init_secp256k1();
100572
- init_utils();
100578
+
100579
+ // ../bitcoin/dist/esm/index.js
100580
+ init_shim();
100581
+
100582
+ // ../bitcoin/dist/esm/connection.js
100583
+ init_shim();
100584
+
100585
+ // ../bitcoin/dist/esm/client/rest/index.js
100586
+ init_shim();
100587
+
100588
+ // ../bitcoin/dist/esm/client/rest/address.js
100589
+ init_shim();
100590
+
100591
+ // ../bitcoin/dist/esm/client/rest/block.js
100592
+ init_shim();
100593
+
100594
+ // ../bitcoin/dist/esm/errors.js
100595
+ init_shim();
100596
+
100597
+ // ../bitcoin/dist/esm/client/rest/transaction.js
100598
+ init_shim();
100599
+
100600
+ // ../bitcoin/dist/esm/client/rest/protocol.js
100601
+ init_shim();
100602
+
100603
+ // ../bitcoin/dist/esm/client/http.js
100604
+ init_shim();
100605
+
100606
+ // ../bitcoin/dist/esm/client/rpc/index.js
100607
+ init_shim();
100608
+
100609
+ // ../bitcoin/dist/esm/client/rpc/json-rpc.js
100610
+ init_shim();
100611
+
100612
+ // ../bitcoin/dist/esm/client/utils.js
100613
+ init_shim();
100614
+
100615
+ // ../bitcoin/dist/esm/client/rpc/protocol.js
100616
+ init_shim();
100617
+
100618
+ // ../bitcoin/dist/esm/network.js
100619
+ init_shim();
100573
100620
 
100574
100621
  // ../../node_modules/.pnpm/@scure+btc-signer@1.8.1/node_modules/@scure/btc-signer/esm/index.js
100575
100622
  init_shim();
@@ -102768,6 +102815,48 @@ var Transaction = class _Transaction {
102768
102815
  }
102769
102816
  };
102770
102817
 
102818
+ // ../bitcoin/dist/esm/network.js
102819
+ var REGTEST_NETWORK = {
102820
+ bech32: "bcrt",
102821
+ pubKeyHash: 111,
102822
+ scriptHash: 196,
102823
+ wif: 239
102824
+ };
102825
+ function getNetwork(network) {
102826
+ switch (network) {
102827
+ case "bitcoin":
102828
+ return NETWORK;
102829
+ case "testnet3":
102830
+ case "testnet4":
102831
+ case "signet":
102832
+ case "mutinynet":
102833
+ return TEST_NETWORK;
102834
+ case "regtest":
102835
+ return REGTEST_NETWORK;
102836
+ default:
102837
+ throw new Error(`Unknown network "${network}"`);
102838
+ }
102839
+ }
102840
+
102841
+ // ../bitcoin/dist/esm/constants.js
102842
+ init_shim();
102843
+ var TXIN_WITNESS_COINBASE = "0000000000000000000000000000000000000000000000000000000000000000";
102844
+ var GENESIS_TX_ID = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b";
102845
+
102846
+ // ../bitcoin/dist/esm/types.js
102847
+ init_shim();
102848
+ var VerbosityLevel;
102849
+ (function(VerbosityLevel2) {
102850
+ VerbosityLevel2[VerbosityLevel2["hex"] = 0] = "hex";
102851
+ VerbosityLevel2[VerbosityLevel2["json"] = 1] = "json";
102852
+ VerbosityLevel2[VerbosityLevel2["jsonext"] = 2] = "jsonext";
102853
+ VerbosityLevel2[VerbosityLevel2["jsonextprev"] = 3] = "jsonextprev";
102854
+ })(VerbosityLevel || (VerbosityLevel = {}));
102855
+
102856
+ // src/core/aggregation/cohort.ts
102857
+ init_secp256k1();
102858
+ init_utils();
102859
+
102771
102860
  // ../../node_modules/.pnpm/@scure+btc-signer@1.8.1/node_modules/@scure/btc-signer/esm/musig2.js
102772
102861
  init_shim();
102773
102862
  init_modular();
@@ -103182,7 +103271,7 @@ var AggregationCohort = class {
103182
103271
  }
103183
103272
  const keyAggContext = keyAggregate(this.#cohortKeys);
103184
103273
  const aggPubkey = keyAggExport(keyAggContext);
103185
- const payment = p2tr(aggPubkey);
103274
+ const payment = p2tr(aggPubkey, void 0, getNetwork(this.network));
103186
103275
  this.tapTweak = schnorr2.utils.taggedHash("TapTweak", aggPubkey);
103187
103276
  if (!payment.address) {
103188
103277
  throw new AggregationCohortError(
@@ -103479,8 +103568,14 @@ var BeaconSigningSession = class {
103479
103568
  signature;
103480
103569
  /** Current signing session phase. */
103481
103570
  phase;
103482
- /** Participant's secret nonce (held only by the participant during signing). */
103483
- secretNonce;
103571
+ /**
103572
+ * Participant's MuSig2 secret nonce, held only on the participant side
103573
+ * between {@link generateNonceContribution} and {@link generatePartialSignature}.
103574
+ * Private and cleared on every terminal path (success, failure, or teardown
103575
+ * via {@link clearSecrets}) so a spent or abandoned nonce cannot be reused or
103576
+ * serialized.
103577
+ */
103578
+ #secretNonce;
103484
103579
  constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }) {
103485
103580
  this.id = id || crypto.randomUUID();
103486
103581
  this.cohort = cohort;
@@ -103632,22 +103727,24 @@ var BeaconSigningSession = class {
103632
103727
  generateNonceContribution(participantPublicKey, participantSecretKey) {
103633
103728
  const aggPublicKey = keyAggExport(keyAggregate(this.cohort.cohortKeys));
103634
103729
  const nonces = nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
103635
- this.secretNonce = nonces.secret;
103730
+ this.#secretNonce = nonces.secret;
103636
103731
  return nonces.public;
103637
103732
  }
103638
103733
  /**
103639
103734
  * Generates a partial signature using the participant's secret key + secret nonce.
103640
103735
  * Requires the aggregated nonce to have been set first (via the service).
103641
103736
  *
103642
- * Zeros the stored `secretNonce` after use. JS cannot truly erase memory (GC
103643
- * and immutable strings), but overwriting the bytes shortens the exposure
103644
- * window and prevents accidental reuse or serialization of a spent nonce.
103737
+ * Clears the stored secret nonce after use on every path (success or throw)
103738
+ * via {@link clearSecrets}. JS cannot truly erase memory (GC may relocate
103739
+ * buffers), but overwriting the bytes shortens the exposure window and
103740
+ * prevents accidental reuse or serialization of a spent nonce - reuse of a
103741
+ * MuSig2 nonce leaks the secret key.
103645
103742
  */
103646
103743
  generatePartialSignature(participantSecretKey) {
103647
103744
  if (!this.aggregatedNonce) {
103648
103745
  throw new SigningSessionError("Aggregated nonce not available.", "MISSING_AGGREGATED_NONCE");
103649
103746
  }
103650
- if (!this.secretNonce) {
103747
+ if (!this.#secretNonce) {
103651
103748
  throw new SigningSessionError("Secret nonce not available \u2014 generateNonceContribution() must be called first.", "MISSING_SECRET_NONCE");
103652
103749
  }
103653
103750
  const session = new Session(
@@ -103657,10 +103754,23 @@ var BeaconSigningSession = class {
103657
103754
  [this.cohort.tapTweak],
103658
103755
  [true]
103659
103756
  );
103660
- const partialSig = session.sign(this.secretNonce, participantSecretKey);
103661
- this.secretNonce.fill(0);
103662
- this.secretNonce = void 0;
103663
- return partialSig;
103757
+ try {
103758
+ return session.sign(this.#secretNonce, participantSecretKey);
103759
+ } finally {
103760
+ this.clearSecrets();
103761
+ }
103762
+ }
103763
+ /**
103764
+ * Zeroize any retained secret nonce. Safe to call repeatedly and on any path
103765
+ * (completion, failure, or teardown of an abandoned session). Callers that
103766
+ * drop a session before it reaches a partial signature should invoke this so
103767
+ * the secret nonce does not linger on the live object.
103768
+ */
103769
+ clearSecrets() {
103770
+ if (this.#secretNonce) {
103771
+ wipe(this.#secretNonce);
103772
+ this.#secretNonce = void 0;
103773
+ }
103664
103774
  }
103665
103775
  isComplete() {
103666
103776
  return this.phase === "Complete" /* Complete */;
@@ -103674,13 +103784,13 @@ var BeaconSigningSession = class {
103674
103784
  var DEFAULT_MAX_UPDATE_SIZE_BYTES = 256 * 1024;
103675
103785
  var AggregationService = class {
103676
103786
  did;
103677
- keys;
103787
+ publicKey;
103678
103788
  maxUpdateSizeBytes;
103679
103789
  /** Per-cohort state, keyed by cohortId. */
103680
103790
  #cohortStates = /* @__PURE__ */ new Map();
103681
- constructor({ did, keys, maxUpdateSizeBytes }) {
103791
+ constructor({ did, publicKey: publicKey2, maxUpdateSizeBytes }) {
103682
103792
  this.did = did;
103683
- this.keys = keys;
103793
+ this.publicKey = publicKey2;
103684
103794
  this.maxUpdateSizeBytes = maxUpdateSizeBytes ?? DEFAULT_MAX_UPDATE_SIZE_BYTES;
103685
103795
  }
103686
103796
  receive(message2) {
@@ -103773,7 +103883,7 @@ var AggregationService = class {
103773
103883
  cohortSize: state.config.minParticipants,
103774
103884
  beaconType: state.config.beaconType,
103775
103885
  network: state.config.network,
103776
- communicationPk: this.keys.publicKey.compressed
103886
+ communicationPk: this.publicKey.compressed
103777
103887
  });
103778
103888
  state.phase = "Advertised" /* Advertised */;
103779
103889
  return [message2];
@@ -104184,12 +104294,17 @@ init_shim();
104184
104294
  init_utils();
104185
104295
  var AggregationParticipant = class {
104186
104296
  did;
104187
- keys;
104297
+ /** MuSig2 signing capability. The raw secret never lives as a field here. */
104298
+ #signer;
104188
104299
  /** Per-cohort state, keyed by cohortId. */
104189
104300
  #cohortStates = /* @__PURE__ */ new Map();
104190
- constructor({ did, keys }) {
104301
+ constructor({ did, signer }) {
104191
104302
  this.did = did;
104192
- this.keys = keys;
104303
+ this.#signer = signer;
104304
+ }
104305
+ /** The participant's compressed (33-byte) MuSig2 public key. Not secret. */
104306
+ get publicKey() {
104307
+ return this.#signer.publicKey;
104193
104308
  }
104194
104309
  /**
104195
104310
  * Process an incoming message. Updates internal state but never produces
@@ -104278,8 +104393,8 @@ var AggregationParticipant = class {
104278
104393
  from: this.did,
104279
104394
  to: state.serviceDid,
104280
104395
  cohortId,
104281
- participantPk: this.keys.publicKey.compressed,
104282
- communicationPk: this.keys.publicKey.compressed
104396
+ participantPk: this.publicKey,
104397
+ communicationPk: this.publicKey
104283
104398
  });
104284
104399
  return [optInMessage];
104285
104400
  }
@@ -104309,7 +104424,7 @@ var AggregationParticipant = class {
104309
104424
  const beaconAddress = message2.body?.beaconAddress;
104310
104425
  const cohortKeys = message2.body?.cohortKeys;
104311
104426
  if (!beaconAddress || !cohortKeys) return;
104312
- const participantPkHex = bytesToHex(this.keys.publicKey.compressed);
104427
+ const participantPkHex = bytesToHex(this.publicKey);
104313
104428
  const cohortKeysHex = cohortKeys.map((k) => bytesToHex(new Uint8Array(k)));
104314
104429
  state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
104315
104430
  state.phase = "CohortReady" /* CohortReady */;
@@ -104476,9 +104591,8 @@ var AggregationParticipant = class {
104476
104591
  prevOutValues
104477
104592
  });
104478
104593
  state.signingSession = session;
104479
- const nonceContribution = session.generateNonceContribution(
104480
- this.keys.publicKey.compressed,
104481
- this.keys.secretKey.bytes
104594
+ const nonceContribution = this.#signer.withSecret(
104595
+ (secretKey) => session.generateNonceContribution(this.publicKey, secretKey)
104482
104596
  );
104483
104597
  state.phase = "NonceSent" /* NonceSent */;
104484
104598
  return [createNonceContributionMessage({
@@ -104521,7 +104635,10 @@ var AggregationParticipant = class {
104521
104635
  { cohortId }
104522
104636
  );
104523
104637
  }
104524
- const partialSig = state.signingSession.generatePartialSignature(this.keys.secretKey.bytes);
104638
+ const signingSession = state.signingSession;
104639
+ const partialSig = this.#signer.withSecret(
104640
+ (secretKey) => signingSession.generatePartialSignature(secretKey)
104641
+ );
104525
104642
  state.phase = "Complete" /* Complete */;
104526
104643
  return [createSignatureAuthorizationMessage({
104527
104644
  from: this.did,
@@ -104534,6 +104651,37 @@ var AggregationParticipant = class {
104534
104651
  getCohortPhase(cohortId) {
104535
104652
  return this.#cohortStates.get(cohortId)?.phase;
104536
104653
  }
104654
+ /**
104655
+ * Zeroize any retained MuSig2 secret nonces across all cohorts. The raw
104656
+ * signing key is never held here (it lives behind the {@link AggregationSigner}
104657
+ * and is wiped per-operation), but an abandoned signing session can still hold
104658
+ * a secret nonce; call this on teardown to clear it deterministically.
104659
+ */
104660
+ clearSecrets() {
104661
+ for (const state of this.#cohortStates.values()) {
104662
+ state.signingSession?.clearSecrets();
104663
+ }
104664
+ }
104665
+ };
104666
+
104667
+ // src/core/aggregation/signer.ts
104668
+ init_shim();
104669
+ var KeyPairAggregationSigner = class {
104670
+ publicKey;
104671
+ #keys;
104672
+ /** @param {SchnorrKeyPair} keys The keypair whose secret backs this signer. */
104673
+ constructor(keys) {
104674
+ this.#keys = keys;
104675
+ this.publicKey = keys.publicKey.compressed;
104676
+ }
104677
+ withSecret(fn) {
104678
+ const secretKey = this.#keys.secretKey.bytes;
104679
+ try {
104680
+ return fn(secretKey);
104681
+ } finally {
104682
+ wipe(secretKey);
104683
+ }
104684
+ }
104537
104685
  };
104538
104686
 
104539
104687
  // src/core/aggregation/logger.ts
@@ -105290,7 +105438,7 @@ var HttpClientTransport = class {
105290
105438
  body: JSON.stringify(envelope)
105291
105439
  });
105292
105440
  if (!res.ok) {
105293
- const body = await safeText(res);
105441
+ const body = await safeText2(res);
105294
105442
  throw new HttpTransportError(
105295
105443
  `sendMessage failed: HTTP ${res.status}`,
105296
105444
  "SEND_MESSAGE_HTTP",
@@ -105467,7 +105615,7 @@ function sleep(ms2, signal) {
105467
105615
  else signal.addEventListener("abort", onAbort, { once: true });
105468
105616
  });
105469
105617
  }
105470
- async function safeText(res) {
105618
+ async function safeText2(res) {
105471
105619
  try {
105472
105620
  return await res.text();
105473
105621
  } catch {
@@ -110994,6 +111142,120 @@ var TransportFactory = class {
110994
111142
  }
110995
111143
  };
110996
111144
 
111145
+ // src/core/aggregation/transport/in-memory.ts
111146
+ init_shim();
111147
+ init_utils();
111148
+ var InMemoryBus = class {
111149
+ #transports = /* @__PURE__ */ new Set();
111150
+ /** Attach a transport to this bus. Called by the transport's constructor. */
111151
+ register(transport) {
111152
+ this.#transports.add(transport);
111153
+ }
111154
+ /** Detach a transport from this bus. */
111155
+ unregister(transport) {
111156
+ this.#transports.delete(transport);
111157
+ }
111158
+ /**
111159
+ * Deliver a message. With no `recipient` the message is broadcast to every
111160
+ * actor on the bus; otherwise it is routed to the single transport that owns
111161
+ * the recipient DID.
111162
+ */
111163
+ async deliver(message2, _sender, recipient) {
111164
+ const type = message2.type;
111165
+ if (!type) return;
111166
+ const replacer = (_k, v) => v instanceof Uint8Array ? { __bytes: bytesToHex(v) } : v;
111167
+ const reviver = (_k, v) => v && typeof v === "object" && "__bytes" in v ? hexToBytes(v.__bytes) : v;
111168
+ const raw = JSON.parse(JSON.stringify(message2, replacer), reviver);
111169
+ const serialized = { ...raw, ...raw.body ?? {} };
111170
+ if (!recipient) {
111171
+ for (const t2 of this.#transports) {
111172
+ await t2.dispatchBroadcast(type, serialized);
111173
+ }
111174
+ return;
111175
+ }
111176
+ for (const t2 of this.#transports) {
111177
+ if (t2.hasActor(recipient)) {
111178
+ await t2.dispatchDirected(recipient, type, serialized);
111179
+ return;
111180
+ }
111181
+ }
111182
+ }
111183
+ };
111184
+ var InMemoryTransport = class {
111185
+ name = "in-memory";
111186
+ bus;
111187
+ #actors = /* @__PURE__ */ new Map();
111188
+ #peers = /* @__PURE__ */ new Map();
111189
+ /** @param bus Shared bus. Pass the same bus to connect multiple transports. */
111190
+ constructor(bus = new InMemoryBus()) {
111191
+ this.bus = bus;
111192
+ this.bus.register(this);
111193
+ }
111194
+ start() {
111195
+ }
111196
+ registerActor(did, keys) {
111197
+ this.#actors.set(did, { publicKey: keys.publicKey.compressed, handlers: /* @__PURE__ */ new Map() });
111198
+ }
111199
+ getActorPk(did) {
111200
+ return this.#actors.get(did)?.publicKey;
111201
+ }
111202
+ /** True if `did` is registered on this transport. Used by the bus for routing. */
111203
+ hasActor(did) {
111204
+ return this.#actors.has(did);
111205
+ }
111206
+ registerPeer(did, communicationPk) {
111207
+ this.#peers.set(did, communicationPk);
111208
+ }
111209
+ getPeerPk(did) {
111210
+ return this.#peers.get(did);
111211
+ }
111212
+ registerMessageHandler(actorDid, messageType, handler) {
111213
+ const actor = this.#actors.get(actorDid);
111214
+ if (actor) actor.handlers.set(messageType, handler);
111215
+ }
111216
+ unregisterMessageHandler(actorDid, messageType) {
111217
+ const actor = this.#actors.get(actorDid);
111218
+ if (actor) actor.handlers.delete(messageType);
111219
+ }
111220
+ unregisterActor(did) {
111221
+ const actor = this.#actors.get(did);
111222
+ if (!actor) return;
111223
+ actor.handlers.clear();
111224
+ this.#actors.delete(did);
111225
+ this.#peers.delete(did);
111226
+ }
111227
+ async sendMessage(message2, sender, recipient) {
111228
+ await this.bus.deliver(message2, sender, recipient);
111229
+ }
111230
+ publishRepeating(message2, sender, intervalMs, recipient) {
111231
+ let stopped = false;
111232
+ void this.sendMessage(message2, sender, recipient).catch(() => {
111233
+ });
111234
+ const timer = setInterval(() => {
111235
+ if (stopped) return;
111236
+ void this.sendMessage(message2, sender, recipient).catch(() => {
111237
+ });
111238
+ }, intervalMs);
111239
+ return () => {
111240
+ if (stopped) return;
111241
+ stopped = true;
111242
+ clearInterval(timer);
111243
+ };
111244
+ }
111245
+ /** Deliver a broadcast message to every actor on this transport that handles `type`. */
111246
+ async dispatchBroadcast(type, message2) {
111247
+ for (const actor of this.#actors.values()) {
111248
+ const handler = actor.handlers.get(type);
111249
+ if (handler) await handler(message2);
111250
+ }
111251
+ }
111252
+ /** Deliver a directed message to the recipient actor's handler for `type`. */
111253
+ async dispatchDirected(recipientDid, type, message2) {
111254
+ const handler = this.#actors.get(recipientDid)?.handlers.get(type);
111255
+ if (handler) await handler(message2);
111256
+ }
111257
+ };
111258
+
110997
111259
  // src/core/aggregation/transport/didcomm.ts
110998
111260
  init_shim();
110999
111261
  var DidCommTransport = class {
@@ -111158,8 +111420,11 @@ var AggregationServiceRunner = class _AggregationServiceRunner extends TypedEven
111158
111420
  this.#phaseTimeoutMs = options2.phaseTimeoutMs;
111159
111421
  this.#advertRepeatIntervalMs = options2.advertRepeatIntervalMs ?? DEFAULT_ADVERT_REPEAT_INTERVAL_MS;
111160
111422
  this.session = new AggregationService({
111423
+ // The coordinator never signs, so the state machine receives only the
111424
+ // public half of the operator's keypair (see ADR 038). The full keypair
111425
+ // remains the operator's transport/communication identity.
111161
111426
  did: options2.did,
111162
- keys: options2.keys,
111427
+ publicKey: options2.keys.publicKey,
111163
111428
  maxUpdateSizeBytes: options2.maxUpdateSizeBytes
111164
111429
  });
111165
111430
  }
@@ -111512,7 +111777,10 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
111512
111777
  this.#onProvideUpdate = options2.onProvideUpdate;
111513
111778
  this.#onValidateData = options2.onValidateData ?? (async (info) => ({ approved: info.matches }));
111514
111779
  this.#onApproveSigning = options2.onApproveSigning ?? (async () => ({ approved: true }));
111515
- this.session = new AggregationParticipant({ did: options2.did, keys: options2.keys });
111780
+ this.session = new AggregationParticipant({
111781
+ did: options2.did,
111782
+ signer: new KeyPairAggregationSigner(options2.keys)
111783
+ });
111516
111784
  }
111517
111785
  /**
111518
111786
  * Start listening for cohorts. The runner stays active until {@link stop}
@@ -111525,6 +111793,7 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
111525
111793
  stop() {
111526
111794
  this.#stopped = true;
111527
111795
  this.#unregisterHandlers();
111796
+ this.session.clearSecrets();
111528
111797
  }
111529
111798
  /** Message types this runner listens for on the transport. */
111530
111799
  static #HANDLED_MESSAGE_TYPES = [
@@ -111734,6 +112003,63 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
111734
112003
  }
111735
112004
  };
111736
112005
 
112006
+ // src/core/aggregation/runner/aggregation-runner.ts
112007
+ init_shim();
112008
+ var AggregationRunner = class {
112009
+ /**
112010
+ * Run a cohort of ONE participant entirely in-process and return the
112011
+ * aggregated MuSig2 result.
112012
+ *
112013
+ * One party plays both the coordinating service and the lone participant,
112014
+ * connected over an {@link InMemoryTransport} (no relay or HTTP server). This
112015
+ * makes the single-participant aggregate-beacon path — the N=1 corner of the
112016
+ * two-axis beacon matrix (see ADR 037) — first-class, useful for generating
112017
+ * and reproducing single-participant aggregate test vectors.
112018
+ *
112019
+ * The service advertises a cohort with `minParticipants: 1`; the participant
112020
+ * joins, submits its update, and the two complete keygen, data distribution,
112021
+ * validation, and a one-signer MuSig2 P2TR key-path signing round.
112022
+ *
112023
+ * @param options Service + participant identities, cohort config, and the
112024
+ * update / tx-data callbacks.
112025
+ * @returns The {@link AggregationResult} (cohort id, aggregated signature, signed tx).
112026
+ */
112027
+ static async solo(options2) {
112028
+ const transport = new InMemoryTransport(new InMemoryBus());
112029
+ transport.registerActor(options2.service.did, options2.service.keys);
112030
+ transport.registerActor(options2.participant.did, options2.participant.keys);
112031
+ transport.registerPeer(options2.participant.did, options2.participant.keys.publicKey.compressed);
112032
+ transport.registerPeer(options2.service.did, options2.service.keys.publicKey.compressed);
112033
+ transport.start();
112034
+ const service = new AggregationServiceRunner({
112035
+ transport,
112036
+ did: options2.service.did,
112037
+ keys: options2.service.keys,
112038
+ config: { minParticipants: 1, network: options2.config.network, beaconType: options2.config.beaconType },
112039
+ onProvideTxData: options2.onProvideTxData,
112040
+ cohortTtlMs: options2.cohortTtlMs,
112041
+ phaseTimeoutMs: options2.phaseTimeoutMs,
112042
+ // In-process bus with the participant already listening: a single advert
112043
+ // suffices, so disable the republish loop (no dangling interval).
112044
+ advertRepeatIntervalMs: 0
112045
+ });
112046
+ const participant = new AggregationParticipantRunner({
112047
+ transport,
112048
+ did: options2.participant.did,
112049
+ keys: options2.participant.keys,
112050
+ shouldJoin: async () => true,
112051
+ onProvideUpdate: options2.onProvideUpdate
112052
+ });
112053
+ await participant.start();
112054
+ try {
112055
+ return await service.run();
112056
+ } finally {
112057
+ participant.stop();
112058
+ service.stop();
112059
+ }
112060
+ }
112061
+ };
112062
+
111737
112063
  // src/core/beacon/beacon.ts
111738
112064
  init_shim();
111739
112065
  init_utils();
@@ -111904,7 +112230,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
111904
112230
  tx.finalize();
111905
112231
  return tx.hex;
111906
112232
  }
111907
- var Beacon = class {
112233
+ var SinglePartyBeacon = class {
111908
112234
  /**
111909
112235
  * The Beacon service configuration parsed from the DID Document.
111910
112236
  */
@@ -112041,7 +112367,7 @@ var Beacon = class {
112041
112367
 
112042
112368
  // src/core/beacon/cas-beacon.ts
112043
112369
  init_shim();
112044
- var CASBeacon = class extends Beacon {
112370
+ var CASBeacon = class extends SinglePartyBeacon {
112045
112371
  /**
112046
112372
  * Creates an instance of CASBeacon.
112047
112373
  * @param {BeaconService} service The service of the Beacon.
@@ -112101,7 +112427,7 @@ var CASBeacon = class extends Beacon {
112101
112427
  * Creates a CAS Announcement mapping the DID to the update hash, broadcasts the hash of the
112102
112428
  * announcement via OP_RETURN, and optionally publishes the announcement off-chain via the
112103
112429
  * supplied `casPublish` callback. UTXO selection, PSBT construction, fee estimation, signing,
112104
- * and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
112430
+ * and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
112105
112431
  *
112106
112432
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112107
112433
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112129,7 +112455,7 @@ init_shim();
112129
112455
 
112130
112456
  // src/core/beacon/singleton-beacon.ts
112131
112457
  init_shim();
112132
- var SingletonBeacon = class extends Beacon {
112458
+ var SingletonBeacon = class extends SinglePartyBeacon {
112133
112459
  /**
112134
112460
  * Creates an instance of SingletonBeacon.
112135
112461
  * @param {BeaconService} service The BeaconService object representing the funded beacon to announce the update to.
@@ -112166,7 +112492,7 @@ var SingletonBeacon = class extends Beacon {
112166
112492
  *
112167
112493
  * The signal bytes embedded in OP_RETURN are the SHA-256 canonical hash of the signed update.
112168
112494
  * UTXO selection, PSBT construction, fee estimation, signing, and broadcast are delegated to
112169
- * {@link Beacon.buildSignAndBroadcast}.
112495
+ * {@link SinglePartyBeacon.buildSignAndBroadcast}.
112170
112496
  *
112171
112497
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112172
112498
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112185,7 +112511,7 @@ var SingletonBeacon = class extends Beacon {
112185
112511
  // src/core/beacon/smt-beacon.ts
112186
112512
  init_shim();
112187
112513
  init_utils();
112188
- var SMTBeacon = class extends Beacon {
112514
+ var SMTBeacon = class extends SinglePartyBeacon {
112189
112515
  /**
112190
112516
  * Creates an instance of SMTBeacon.
112191
112517
  * @param {BeaconService} service The Beacon service.
@@ -112261,7 +112587,7 @@ var SMTBeacon = class extends Beacon {
112261
112587
  * Builds a single-entry Sparse Merkle Tree from the signed update, then broadcasts the tree's
112262
112588
  * root hash via OP_RETURN. For multi-party aggregation, use the {@link AggregationService}
112263
112589
  * subsystem directly instead of this method. UTXO selection, PSBT construction, fee estimation,
112264
- * signing, and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
112590
+ * signing, and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
112265
112591
  *
112266
112592
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112267
112593
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112287,7 +112613,7 @@ var BeaconFactory = class {
112287
112613
  /**
112288
112614
  * Establish a Beacon instance based on the provided service and optional sidecar data.
112289
112615
  * @param {BeaconService} service The beacon service configuration.
112290
- * @returns {Beacon} The established Beacon instance.
112616
+ * @returns {SinglePartyBeacon} The established Beacon instance.
112291
112617
  */
112292
112618
  static establish(service) {
112293
112619
  switch (service.type) {
@@ -112309,84 +112635,6 @@ init_shim();
112309
112635
  // src/core/beacon/signal-discovery.ts
112310
112636
  init_shim();
112311
112637
 
112312
- // ../bitcoin/dist/esm/index.js
112313
- init_shim();
112314
-
112315
- // ../bitcoin/dist/esm/connection.js
112316
- init_shim();
112317
-
112318
- // ../bitcoin/dist/esm/client/rest/index.js
112319
- init_shim();
112320
-
112321
- // ../bitcoin/dist/esm/client/rest/address.js
112322
- init_shim();
112323
-
112324
- // ../bitcoin/dist/esm/client/rest/block.js
112325
- init_shim();
112326
-
112327
- // ../bitcoin/dist/esm/errors.js
112328
- init_shim();
112329
-
112330
- // ../bitcoin/dist/esm/client/rest/transaction.js
112331
- init_shim();
112332
-
112333
- // ../bitcoin/dist/esm/client/rest/protocol.js
112334
- init_shim();
112335
-
112336
- // ../bitcoin/dist/esm/client/http.js
112337
- init_shim();
112338
-
112339
- // ../bitcoin/dist/esm/client/rpc/index.js
112340
- init_shim();
112341
-
112342
- // ../bitcoin/dist/esm/client/rpc/json-rpc.js
112343
- init_shim();
112344
-
112345
- // ../bitcoin/dist/esm/client/utils.js
112346
- init_shim();
112347
-
112348
- // ../bitcoin/dist/esm/client/rpc/protocol.js
112349
- init_shim();
112350
-
112351
- // ../bitcoin/dist/esm/network.js
112352
- init_shim();
112353
- var REGTEST_NETWORK = {
112354
- bech32: "bcrt",
112355
- pubKeyHash: 111,
112356
- scriptHash: 196,
112357
- wif: 239
112358
- };
112359
- function getNetwork(network) {
112360
- switch (network) {
112361
- case "bitcoin":
112362
- return NETWORK;
112363
- case "testnet3":
112364
- case "testnet4":
112365
- case "signet":
112366
- case "mutinynet":
112367
- return TEST_NETWORK;
112368
- case "regtest":
112369
- return REGTEST_NETWORK;
112370
- default:
112371
- throw new Error(`Unknown network "${network}"`);
112372
- }
112373
- }
112374
-
112375
- // ../bitcoin/dist/esm/constants.js
112376
- init_shim();
112377
- var TXIN_WITNESS_COINBASE = "0000000000000000000000000000000000000000000000000000000000000000";
112378
- var GENESIS_TX_ID = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b";
112379
-
112380
- // ../bitcoin/dist/esm/types.js
112381
- init_shim();
112382
- var VerbosityLevel;
112383
- (function(VerbosityLevel2) {
112384
- VerbosityLevel2[VerbosityLevel2["hex"] = 0] = "hex";
112385
- VerbosityLevel2[VerbosityLevel2["json"] = 1] = "json";
112386
- VerbosityLevel2[VerbosityLevel2["jsonext"] = 2] = "jsonext";
112387
- VerbosityLevel2[VerbosityLevel2["jsonextprev"] = 3] = "jsonextprev";
112388
- })(VerbosityLevel || (VerbosityLevel = {}));
112389
-
112390
112638
  // src/core/beacon/utils.ts
112391
112639
  init_shim();
112392
112640
 
@@ -128807,6 +129055,7 @@ export {
128807
129055
  AggregationParticipant,
128808
129056
  AggregationParticipantError,
128809
129057
  AggregationParticipantRunner,
129058
+ AggregationRunner,
128810
129059
  AggregationService,
128811
129060
  AggregationServiceError,
128812
129061
  AggregationServiceRunner,
@@ -128814,7 +129063,6 @@ export {
128814
129063
  BECH32M_CHARS,
128815
129064
  BTCR2_DID_DOCUMENT_CONTEXT,
128816
129065
  BaseMessage,
128817
- Beacon,
128818
129066
  BeaconError,
128819
129067
  BeaconFactory,
128820
129068
  BeaconSignalDiscovery,
@@ -128849,8 +129097,11 @@ export {
128849
129097
  HttpTransportError,
128850
129098
  ID_PLACEHOLDER_VALUE,
128851
129099
  Identifier,
129100
+ InMemoryBus,
128852
129101
  InMemoryRateLimitStore,
129102
+ InMemoryTransport,
128853
129103
  InboxBuffer,
129104
+ KeyPairAggregationSigner,
128854
129105
  NONCE_CONTRIBUTION,
128855
129106
  NonceCache,
128856
129107
  NostrTransport,
@@ -128871,6 +129122,7 @@ export {
128871
129122
  ServiceCohortPhase,
128872
129123
  SigningSessionError,
128873
129124
  SigningSessionPhase,
129125
+ SinglePartyBeacon,
128874
129126
  SingletonBeacon,
128875
129127
  SingletonBeaconError,
128876
129128
  StaticFeeEstimator,