@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.js CHANGED
@@ -93157,6 +93157,7 @@ a=end-of-candidates
93157
93157
  AggregationParticipant: () => AggregationParticipant,
93158
93158
  AggregationParticipantError: () => AggregationParticipantError,
93159
93159
  AggregationParticipantRunner: () => AggregationParticipantRunner,
93160
+ AggregationRunner: () => AggregationRunner,
93160
93161
  AggregationService: () => AggregationService,
93161
93162
  AggregationServiceError: () => AggregationServiceError,
93162
93163
  AggregationServiceRunner: () => AggregationServiceRunner,
@@ -93164,7 +93165,6 @@ a=end-of-candidates
93164
93165
  BECH32M_CHARS: () => BECH32M_CHARS,
93165
93166
  BTCR2_DID_DOCUMENT_CONTEXT: () => BTCR2_DID_DOCUMENT_CONTEXT,
93166
93167
  BaseMessage: () => BaseMessage,
93167
- Beacon: () => Beacon,
93168
93168
  BeaconError: () => BeaconError,
93169
93169
  BeaconFactory: () => BeaconFactory,
93170
93170
  BeaconSignalDiscovery: () => BeaconSignalDiscovery,
@@ -93199,8 +93199,11 @@ a=end-of-candidates
93199
93199
  HttpTransportError: () => HttpTransportError,
93200
93200
  ID_PLACEHOLDER_VALUE: () => ID_PLACEHOLDER_VALUE,
93201
93201
  Identifier: () => Identifier,
93202
+ InMemoryBus: () => InMemoryBus,
93202
93203
  InMemoryRateLimitStore: () => InMemoryRateLimitStore,
93204
+ InMemoryTransport: () => InMemoryTransport,
93203
93205
  InboxBuffer: () => InboxBuffer,
93206
+ KeyPairAggregationSigner: () => KeyPairAggregationSigner,
93204
93207
  NONCE_CONTRIBUTION: () => NONCE_CONTRIBUTION,
93205
93208
  NonceCache: () => NonceCache,
93206
93209
  NostrTransport: () => NostrTransport,
@@ -93221,6 +93224,7 @@ a=end-of-candidates
93221
93224
  ServiceCohortPhase: () => ServiceCohortPhase,
93222
93225
  SigningSessionError: () => SigningSessionError,
93223
93226
  SigningSessionPhase: () => SigningSessionPhase,
93227
+ SinglePartyBeacon: () => SinglePartyBeacon,
93224
93228
  SingletonBeacon: () => SingletonBeacon,
93225
93229
  SingletonBeaconError: () => SingletonBeaconError,
93226
93230
  StaticFeeEstimator: () => StaticFeeEstimator,
@@ -100114,6 +100118,13 @@ a=end-of-candidates
100114
100118
  // ../keypair/dist/esm/types.js
100115
100119
  init_shim();
100116
100120
 
100121
+ // ../keypair/dist/esm/utils.js
100122
+ init_shim();
100123
+ function wipe(bytes3) {
100124
+ if (bytes3)
100125
+ bytes3.fill(0);
100126
+ }
100127
+
100117
100128
  // ../cryptosuite/dist/esm/multikey/index.js
100118
100129
  init_secp256k1();
100119
100130
  init_utils();
@@ -100700,8 +100711,48 @@ a=end-of-candidates
100700
100711
 
100701
100712
  // src/core/aggregation/cohort.ts
100702
100713
  init_shim();
100703
- init_secp256k1();
100704
- init_utils();
100714
+
100715
+ // ../bitcoin/dist/esm/index.js
100716
+ init_shim();
100717
+
100718
+ // ../bitcoin/dist/esm/connection.js
100719
+ init_shim();
100720
+
100721
+ // ../bitcoin/dist/esm/client/rest/index.js
100722
+ init_shim();
100723
+
100724
+ // ../bitcoin/dist/esm/client/rest/address.js
100725
+ init_shim();
100726
+
100727
+ // ../bitcoin/dist/esm/client/rest/block.js
100728
+ init_shim();
100729
+
100730
+ // ../bitcoin/dist/esm/errors.js
100731
+ init_shim();
100732
+
100733
+ // ../bitcoin/dist/esm/client/rest/transaction.js
100734
+ init_shim();
100735
+
100736
+ // ../bitcoin/dist/esm/client/rest/protocol.js
100737
+ init_shim();
100738
+
100739
+ // ../bitcoin/dist/esm/client/http.js
100740
+ init_shim();
100741
+
100742
+ // ../bitcoin/dist/esm/client/rpc/index.js
100743
+ init_shim();
100744
+
100745
+ // ../bitcoin/dist/esm/client/rpc/json-rpc.js
100746
+ init_shim();
100747
+
100748
+ // ../bitcoin/dist/esm/client/utils.js
100749
+ init_shim();
100750
+
100751
+ // ../bitcoin/dist/esm/client/rpc/protocol.js
100752
+ init_shim();
100753
+
100754
+ // ../bitcoin/dist/esm/network.js
100755
+ init_shim();
100705
100756
 
100706
100757
  // ../../node_modules/.pnpm/@scure+btc-signer@1.8.1/node_modules/@scure/btc-signer/esm/index.js
100707
100758
  init_shim();
@@ -102900,6 +102951,48 @@ a=end-of-candidates
102900
102951
  }
102901
102952
  };
102902
102953
 
102954
+ // ../bitcoin/dist/esm/network.js
102955
+ var REGTEST_NETWORK = {
102956
+ bech32: "bcrt",
102957
+ pubKeyHash: 111,
102958
+ scriptHash: 196,
102959
+ wif: 239
102960
+ };
102961
+ function getNetwork(network) {
102962
+ switch (network) {
102963
+ case "bitcoin":
102964
+ return NETWORK;
102965
+ case "testnet3":
102966
+ case "testnet4":
102967
+ case "signet":
102968
+ case "mutinynet":
102969
+ return TEST_NETWORK;
102970
+ case "regtest":
102971
+ return REGTEST_NETWORK;
102972
+ default:
102973
+ throw new Error(`Unknown network "${network}"`);
102974
+ }
102975
+ }
102976
+
102977
+ // ../bitcoin/dist/esm/constants.js
102978
+ init_shim();
102979
+ var TXIN_WITNESS_COINBASE = "0000000000000000000000000000000000000000000000000000000000000000";
102980
+ var GENESIS_TX_ID = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b";
102981
+
102982
+ // ../bitcoin/dist/esm/types.js
102983
+ init_shim();
102984
+ var VerbosityLevel;
102985
+ (function(VerbosityLevel2) {
102986
+ VerbosityLevel2[VerbosityLevel2["hex"] = 0] = "hex";
102987
+ VerbosityLevel2[VerbosityLevel2["json"] = 1] = "json";
102988
+ VerbosityLevel2[VerbosityLevel2["jsonext"] = 2] = "jsonext";
102989
+ VerbosityLevel2[VerbosityLevel2["jsonextprev"] = 3] = "jsonextprev";
102990
+ })(VerbosityLevel || (VerbosityLevel = {}));
102991
+
102992
+ // src/core/aggregation/cohort.ts
102993
+ init_secp256k1();
102994
+ init_utils();
102995
+
102903
102996
  // ../../node_modules/.pnpm/@scure+btc-signer@1.8.1/node_modules/@scure/btc-signer/esm/musig2.js
102904
102997
  init_shim();
102905
102998
  init_modular();
@@ -103314,7 +103407,7 @@ a=end-of-candidates
103314
103407
  }
103315
103408
  const keyAggContext = keyAggregate(this.#cohortKeys);
103316
103409
  const aggPubkey = keyAggExport(keyAggContext);
103317
- const payment = p2tr(aggPubkey);
103410
+ const payment = p2tr(aggPubkey, void 0, getNetwork(this.network));
103318
103411
  this.tapTweak = schnorr2.utils.taggedHash("TapTweak", aggPubkey);
103319
103412
  if (!payment.address) {
103320
103413
  throw new AggregationCohortError(
@@ -103611,8 +103704,14 @@ a=end-of-candidates
103611
103704
  signature;
103612
103705
  /** Current signing session phase. */
103613
103706
  phase;
103614
- /** Participant's secret nonce (held only by the participant during signing). */
103615
- secretNonce;
103707
+ /**
103708
+ * Participant's MuSig2 secret nonce, held only on the participant side
103709
+ * between {@link generateNonceContribution} and {@link generatePartialSignature}.
103710
+ * Private and cleared on every terminal path (success, failure, or teardown
103711
+ * via {@link clearSecrets}) so a spent or abandoned nonce cannot be reused or
103712
+ * serialized.
103713
+ */
103714
+ #secretNonce;
103616
103715
  constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }) {
103617
103716
  this.id = id || crypto.randomUUID();
103618
103717
  this.cohort = cohort;
@@ -103764,22 +103863,24 @@ a=end-of-candidates
103764
103863
  generateNonceContribution(participantPublicKey, participantSecretKey) {
103765
103864
  const aggPublicKey = keyAggExport(keyAggregate(this.cohort.cohortKeys));
103766
103865
  const nonces = nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
103767
- this.secretNonce = nonces.secret;
103866
+ this.#secretNonce = nonces.secret;
103768
103867
  return nonces.public;
103769
103868
  }
103770
103869
  /**
103771
103870
  * Generates a partial signature using the participant's secret key + secret nonce.
103772
103871
  * Requires the aggregated nonce to have been set first (via the service).
103773
103872
  *
103774
- * Zeros the stored `secretNonce` after use. JS cannot truly erase memory (GC
103775
- * and immutable strings), but overwriting the bytes shortens the exposure
103776
- * window and prevents accidental reuse or serialization of a spent nonce.
103873
+ * Clears the stored secret nonce after use on every path (success or throw)
103874
+ * via {@link clearSecrets}. JS cannot truly erase memory (GC may relocate
103875
+ * buffers), but overwriting the bytes shortens the exposure window and
103876
+ * prevents accidental reuse or serialization of a spent nonce - reuse of a
103877
+ * MuSig2 nonce leaks the secret key.
103777
103878
  */
103778
103879
  generatePartialSignature(participantSecretKey) {
103779
103880
  if (!this.aggregatedNonce) {
103780
103881
  throw new SigningSessionError("Aggregated nonce not available.", "MISSING_AGGREGATED_NONCE");
103781
103882
  }
103782
- if (!this.secretNonce) {
103883
+ if (!this.#secretNonce) {
103783
103884
  throw new SigningSessionError("Secret nonce not available \u2014 generateNonceContribution() must be called first.", "MISSING_SECRET_NONCE");
103784
103885
  }
103785
103886
  const session = new Session(
@@ -103789,10 +103890,23 @@ a=end-of-candidates
103789
103890
  [this.cohort.tapTweak],
103790
103891
  [true]
103791
103892
  );
103792
- const partialSig = session.sign(this.secretNonce, participantSecretKey);
103793
- this.secretNonce.fill(0);
103794
- this.secretNonce = void 0;
103795
- return partialSig;
103893
+ try {
103894
+ return session.sign(this.#secretNonce, participantSecretKey);
103895
+ } finally {
103896
+ this.clearSecrets();
103897
+ }
103898
+ }
103899
+ /**
103900
+ * Zeroize any retained secret nonce. Safe to call repeatedly and on any path
103901
+ * (completion, failure, or teardown of an abandoned session). Callers that
103902
+ * drop a session before it reaches a partial signature should invoke this so
103903
+ * the secret nonce does not linger on the live object.
103904
+ */
103905
+ clearSecrets() {
103906
+ if (this.#secretNonce) {
103907
+ wipe(this.#secretNonce);
103908
+ this.#secretNonce = void 0;
103909
+ }
103796
103910
  }
103797
103911
  isComplete() {
103798
103912
  return this.phase === "Complete" /* Complete */;
@@ -103806,13 +103920,13 @@ a=end-of-candidates
103806
103920
  var DEFAULT_MAX_UPDATE_SIZE_BYTES = 256 * 1024;
103807
103921
  var AggregationService = class {
103808
103922
  did;
103809
- keys;
103923
+ publicKey;
103810
103924
  maxUpdateSizeBytes;
103811
103925
  /** Per-cohort state, keyed by cohortId. */
103812
103926
  #cohortStates = /* @__PURE__ */ new Map();
103813
- constructor({ did, keys, maxUpdateSizeBytes }) {
103927
+ constructor({ did, publicKey: publicKey2, maxUpdateSizeBytes }) {
103814
103928
  this.did = did;
103815
- this.keys = keys;
103929
+ this.publicKey = publicKey2;
103816
103930
  this.maxUpdateSizeBytes = maxUpdateSizeBytes ?? DEFAULT_MAX_UPDATE_SIZE_BYTES;
103817
103931
  }
103818
103932
  receive(message2) {
@@ -103905,7 +104019,7 @@ a=end-of-candidates
103905
104019
  cohortSize: state.config.minParticipants,
103906
104020
  beaconType: state.config.beaconType,
103907
104021
  network: state.config.network,
103908
- communicationPk: this.keys.publicKey.compressed
104022
+ communicationPk: this.publicKey.compressed
103909
104023
  });
103910
104024
  state.phase = "Advertised" /* Advertised */;
103911
104025
  return [message2];
@@ -104316,12 +104430,17 @@ a=end-of-candidates
104316
104430
  init_utils();
104317
104431
  var AggregationParticipant = class {
104318
104432
  did;
104319
- keys;
104433
+ /** MuSig2 signing capability. The raw secret never lives as a field here. */
104434
+ #signer;
104320
104435
  /** Per-cohort state, keyed by cohortId. */
104321
104436
  #cohortStates = /* @__PURE__ */ new Map();
104322
- constructor({ did, keys }) {
104437
+ constructor({ did, signer }) {
104323
104438
  this.did = did;
104324
- this.keys = keys;
104439
+ this.#signer = signer;
104440
+ }
104441
+ /** The participant's compressed (33-byte) MuSig2 public key. Not secret. */
104442
+ get publicKey() {
104443
+ return this.#signer.publicKey;
104325
104444
  }
104326
104445
  /**
104327
104446
  * Process an incoming message. Updates internal state but never produces
@@ -104410,8 +104529,8 @@ a=end-of-candidates
104410
104529
  from: this.did,
104411
104530
  to: state.serviceDid,
104412
104531
  cohortId,
104413
- participantPk: this.keys.publicKey.compressed,
104414
- communicationPk: this.keys.publicKey.compressed
104532
+ participantPk: this.publicKey,
104533
+ communicationPk: this.publicKey
104415
104534
  });
104416
104535
  return [optInMessage];
104417
104536
  }
@@ -104441,7 +104560,7 @@ a=end-of-candidates
104441
104560
  const beaconAddress = message2.body?.beaconAddress;
104442
104561
  const cohortKeys = message2.body?.cohortKeys;
104443
104562
  if (!beaconAddress || !cohortKeys) return;
104444
- const participantPkHex = bytesToHex(this.keys.publicKey.compressed);
104563
+ const participantPkHex = bytesToHex(this.publicKey);
104445
104564
  const cohortKeysHex = cohortKeys.map((k) => bytesToHex(new Uint8Array(k)));
104446
104565
  state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
104447
104566
  state.phase = "CohortReady" /* CohortReady */;
@@ -104608,9 +104727,8 @@ a=end-of-candidates
104608
104727
  prevOutValues
104609
104728
  });
104610
104729
  state.signingSession = session;
104611
- const nonceContribution = session.generateNonceContribution(
104612
- this.keys.publicKey.compressed,
104613
- this.keys.secretKey.bytes
104730
+ const nonceContribution = this.#signer.withSecret(
104731
+ (secretKey) => session.generateNonceContribution(this.publicKey, secretKey)
104614
104732
  );
104615
104733
  state.phase = "NonceSent" /* NonceSent */;
104616
104734
  return [createNonceContributionMessage({
@@ -104653,7 +104771,10 @@ a=end-of-candidates
104653
104771
  { cohortId }
104654
104772
  );
104655
104773
  }
104656
- const partialSig = state.signingSession.generatePartialSignature(this.keys.secretKey.bytes);
104774
+ const signingSession = state.signingSession;
104775
+ const partialSig = this.#signer.withSecret(
104776
+ (secretKey) => signingSession.generatePartialSignature(secretKey)
104777
+ );
104657
104778
  state.phase = "Complete" /* Complete */;
104658
104779
  return [createSignatureAuthorizationMessage({
104659
104780
  from: this.did,
@@ -104666,6 +104787,37 @@ a=end-of-candidates
104666
104787
  getCohortPhase(cohortId) {
104667
104788
  return this.#cohortStates.get(cohortId)?.phase;
104668
104789
  }
104790
+ /**
104791
+ * Zeroize any retained MuSig2 secret nonces across all cohorts. The raw
104792
+ * signing key is never held here (it lives behind the {@link AggregationSigner}
104793
+ * and is wiped per-operation), but an abandoned signing session can still hold
104794
+ * a secret nonce; call this on teardown to clear it deterministically.
104795
+ */
104796
+ clearSecrets() {
104797
+ for (const state of this.#cohortStates.values()) {
104798
+ state.signingSession?.clearSecrets();
104799
+ }
104800
+ }
104801
+ };
104802
+
104803
+ // src/core/aggregation/signer.ts
104804
+ init_shim();
104805
+ var KeyPairAggregationSigner = class {
104806
+ publicKey;
104807
+ #keys;
104808
+ /** @param {SchnorrKeyPair} keys The keypair whose secret backs this signer. */
104809
+ constructor(keys) {
104810
+ this.#keys = keys;
104811
+ this.publicKey = keys.publicKey.compressed;
104812
+ }
104813
+ withSecret(fn) {
104814
+ const secretKey = this.#keys.secretKey.bytes;
104815
+ try {
104816
+ return fn(secretKey);
104817
+ } finally {
104818
+ wipe(secretKey);
104819
+ }
104820
+ }
104669
104821
  };
104670
104822
 
104671
104823
  // src/core/aggregation/logger.ts
@@ -105422,7 +105574,7 @@ ${value2}`;
105422
105574
  body: JSON.stringify(envelope)
105423
105575
  });
105424
105576
  if (!res.ok) {
105425
- const body = await safeText(res);
105577
+ const body = await safeText2(res);
105426
105578
  throw new HttpTransportError(
105427
105579
  `sendMessage failed: HTTP ${res.status}`,
105428
105580
  "SEND_MESSAGE_HTTP",
@@ -105599,7 +105751,7 @@ ${value2}`;
105599
105751
  else signal.addEventListener("abort", onAbort, { once: true });
105600
105752
  });
105601
105753
  }
105602
- async function safeText(res) {
105754
+ async function safeText2(res) {
105603
105755
  try {
105604
105756
  return await res.text();
105605
105757
  } catch {
@@ -111126,6 +111278,120 @@ ${value2}`;
111126
111278
  }
111127
111279
  };
111128
111280
 
111281
+ // src/core/aggregation/transport/in-memory.ts
111282
+ init_shim();
111283
+ init_utils();
111284
+ var InMemoryBus = class {
111285
+ #transports = /* @__PURE__ */ new Set();
111286
+ /** Attach a transport to this bus. Called by the transport's constructor. */
111287
+ register(transport) {
111288
+ this.#transports.add(transport);
111289
+ }
111290
+ /** Detach a transport from this bus. */
111291
+ unregister(transport) {
111292
+ this.#transports.delete(transport);
111293
+ }
111294
+ /**
111295
+ * Deliver a message. With no `recipient` the message is broadcast to every
111296
+ * actor on the bus; otherwise it is routed to the single transport that owns
111297
+ * the recipient DID.
111298
+ */
111299
+ async deliver(message2, _sender, recipient) {
111300
+ const type = message2.type;
111301
+ if (!type) return;
111302
+ const replacer = (_k, v) => v instanceof Uint8Array ? { __bytes: bytesToHex(v) } : v;
111303
+ const reviver = (_k, v) => v && typeof v === "object" && "__bytes" in v ? hexToBytes(v.__bytes) : v;
111304
+ const raw = JSON.parse(JSON.stringify(message2, replacer), reviver);
111305
+ const serialized = { ...raw, ...raw.body ?? {} };
111306
+ if (!recipient) {
111307
+ for (const t2 of this.#transports) {
111308
+ await t2.dispatchBroadcast(type, serialized);
111309
+ }
111310
+ return;
111311
+ }
111312
+ for (const t2 of this.#transports) {
111313
+ if (t2.hasActor(recipient)) {
111314
+ await t2.dispatchDirected(recipient, type, serialized);
111315
+ return;
111316
+ }
111317
+ }
111318
+ }
111319
+ };
111320
+ var InMemoryTransport = class {
111321
+ name = "in-memory";
111322
+ bus;
111323
+ #actors = /* @__PURE__ */ new Map();
111324
+ #peers = /* @__PURE__ */ new Map();
111325
+ /** @param bus Shared bus. Pass the same bus to connect multiple transports. */
111326
+ constructor(bus = new InMemoryBus()) {
111327
+ this.bus = bus;
111328
+ this.bus.register(this);
111329
+ }
111330
+ start() {
111331
+ }
111332
+ registerActor(did, keys) {
111333
+ this.#actors.set(did, { publicKey: keys.publicKey.compressed, handlers: /* @__PURE__ */ new Map() });
111334
+ }
111335
+ getActorPk(did) {
111336
+ return this.#actors.get(did)?.publicKey;
111337
+ }
111338
+ /** True if `did` is registered on this transport. Used by the bus for routing. */
111339
+ hasActor(did) {
111340
+ return this.#actors.has(did);
111341
+ }
111342
+ registerPeer(did, communicationPk) {
111343
+ this.#peers.set(did, communicationPk);
111344
+ }
111345
+ getPeerPk(did) {
111346
+ return this.#peers.get(did);
111347
+ }
111348
+ registerMessageHandler(actorDid, messageType, handler) {
111349
+ const actor = this.#actors.get(actorDid);
111350
+ if (actor) actor.handlers.set(messageType, handler);
111351
+ }
111352
+ unregisterMessageHandler(actorDid, messageType) {
111353
+ const actor = this.#actors.get(actorDid);
111354
+ if (actor) actor.handlers.delete(messageType);
111355
+ }
111356
+ unregisterActor(did) {
111357
+ const actor = this.#actors.get(did);
111358
+ if (!actor) return;
111359
+ actor.handlers.clear();
111360
+ this.#actors.delete(did);
111361
+ this.#peers.delete(did);
111362
+ }
111363
+ async sendMessage(message2, sender, recipient) {
111364
+ await this.bus.deliver(message2, sender, recipient);
111365
+ }
111366
+ publishRepeating(message2, sender, intervalMs, recipient) {
111367
+ let stopped = false;
111368
+ void this.sendMessage(message2, sender, recipient).catch(() => {
111369
+ });
111370
+ const timer = setInterval(() => {
111371
+ if (stopped) return;
111372
+ void this.sendMessage(message2, sender, recipient).catch(() => {
111373
+ });
111374
+ }, intervalMs);
111375
+ return () => {
111376
+ if (stopped) return;
111377
+ stopped = true;
111378
+ clearInterval(timer);
111379
+ };
111380
+ }
111381
+ /** Deliver a broadcast message to every actor on this transport that handles `type`. */
111382
+ async dispatchBroadcast(type, message2) {
111383
+ for (const actor of this.#actors.values()) {
111384
+ const handler = actor.handlers.get(type);
111385
+ if (handler) await handler(message2);
111386
+ }
111387
+ }
111388
+ /** Deliver a directed message to the recipient actor's handler for `type`. */
111389
+ async dispatchDirected(recipientDid, type, message2) {
111390
+ const handler = this.#actors.get(recipientDid)?.handlers.get(type);
111391
+ if (handler) await handler(message2);
111392
+ }
111393
+ };
111394
+
111129
111395
  // src/core/aggregation/transport/didcomm.ts
111130
111396
  init_shim();
111131
111397
  var DidCommTransport = class {
@@ -111290,8 +111556,11 @@ ${value2}`;
111290
111556
  this.#phaseTimeoutMs = options2.phaseTimeoutMs;
111291
111557
  this.#advertRepeatIntervalMs = options2.advertRepeatIntervalMs ?? DEFAULT_ADVERT_REPEAT_INTERVAL_MS;
111292
111558
  this.session = new AggregationService({
111559
+ // The coordinator never signs, so the state machine receives only the
111560
+ // public half of the operator's keypair (see ADR 038). The full keypair
111561
+ // remains the operator's transport/communication identity.
111293
111562
  did: options2.did,
111294
- keys: options2.keys,
111563
+ publicKey: options2.keys.publicKey,
111295
111564
  maxUpdateSizeBytes: options2.maxUpdateSizeBytes
111296
111565
  });
111297
111566
  }
@@ -111644,7 +111913,10 @@ ${value2}`;
111644
111913
  this.#onProvideUpdate = options2.onProvideUpdate;
111645
111914
  this.#onValidateData = options2.onValidateData ?? (async (info) => ({ approved: info.matches }));
111646
111915
  this.#onApproveSigning = options2.onApproveSigning ?? (async () => ({ approved: true }));
111647
- this.session = new AggregationParticipant({ did: options2.did, keys: options2.keys });
111916
+ this.session = new AggregationParticipant({
111917
+ did: options2.did,
111918
+ signer: new KeyPairAggregationSigner(options2.keys)
111919
+ });
111648
111920
  }
111649
111921
  /**
111650
111922
  * Start listening for cohorts. The runner stays active until {@link stop}
@@ -111657,6 +111929,7 @@ ${value2}`;
111657
111929
  stop() {
111658
111930
  this.#stopped = true;
111659
111931
  this.#unregisterHandlers();
111932
+ this.session.clearSecrets();
111660
111933
  }
111661
111934
  /** Message types this runner listens for on the transport. */
111662
111935
  static #HANDLED_MESSAGE_TYPES = [
@@ -111866,6 +112139,63 @@ ${value2}`;
111866
112139
  }
111867
112140
  };
111868
112141
 
112142
+ // src/core/aggregation/runner/aggregation-runner.ts
112143
+ init_shim();
112144
+ var AggregationRunner = class {
112145
+ /**
112146
+ * Run a cohort of ONE participant entirely in-process and return the
112147
+ * aggregated MuSig2 result.
112148
+ *
112149
+ * One party plays both the coordinating service and the lone participant,
112150
+ * connected over an {@link InMemoryTransport} (no relay or HTTP server). This
112151
+ * makes the single-participant aggregate-beacon path — the N=1 corner of the
112152
+ * two-axis beacon matrix (see ADR 037) — first-class, useful for generating
112153
+ * and reproducing single-participant aggregate test vectors.
112154
+ *
112155
+ * The service advertises a cohort with `minParticipants: 1`; the participant
112156
+ * joins, submits its update, and the two complete keygen, data distribution,
112157
+ * validation, and a one-signer MuSig2 P2TR key-path signing round.
112158
+ *
112159
+ * @param options Service + participant identities, cohort config, and the
112160
+ * update / tx-data callbacks.
112161
+ * @returns The {@link AggregationResult} (cohort id, aggregated signature, signed tx).
112162
+ */
112163
+ static async solo(options2) {
112164
+ const transport = new InMemoryTransport(new InMemoryBus());
112165
+ transport.registerActor(options2.service.did, options2.service.keys);
112166
+ transport.registerActor(options2.participant.did, options2.participant.keys);
112167
+ transport.registerPeer(options2.participant.did, options2.participant.keys.publicKey.compressed);
112168
+ transport.registerPeer(options2.service.did, options2.service.keys.publicKey.compressed);
112169
+ transport.start();
112170
+ const service = new AggregationServiceRunner({
112171
+ transport,
112172
+ did: options2.service.did,
112173
+ keys: options2.service.keys,
112174
+ config: { minParticipants: 1, network: options2.config.network, beaconType: options2.config.beaconType },
112175
+ onProvideTxData: options2.onProvideTxData,
112176
+ cohortTtlMs: options2.cohortTtlMs,
112177
+ phaseTimeoutMs: options2.phaseTimeoutMs,
112178
+ // In-process bus with the participant already listening: a single advert
112179
+ // suffices, so disable the republish loop (no dangling interval).
112180
+ advertRepeatIntervalMs: 0
112181
+ });
112182
+ const participant = new AggregationParticipantRunner({
112183
+ transport,
112184
+ did: options2.participant.did,
112185
+ keys: options2.participant.keys,
112186
+ shouldJoin: async () => true,
112187
+ onProvideUpdate: options2.onProvideUpdate
112188
+ });
112189
+ await participant.start();
112190
+ try {
112191
+ return await service.run();
112192
+ } finally {
112193
+ participant.stop();
112194
+ service.stop();
112195
+ }
112196
+ }
112197
+ };
112198
+
111869
112199
  // src/core/beacon/beacon.ts
111870
112200
  init_shim();
111871
112201
  init_utils();
@@ -112036,7 +112366,7 @@ ${value2}`;
112036
112366
  tx.finalize();
112037
112367
  return tx.hex;
112038
112368
  }
112039
- var Beacon = class {
112369
+ var SinglePartyBeacon = class {
112040
112370
  /**
112041
112371
  * The Beacon service configuration parsed from the DID Document.
112042
112372
  */
@@ -112173,7 +112503,7 @@ ${value2}`;
112173
112503
 
112174
112504
  // src/core/beacon/cas-beacon.ts
112175
112505
  init_shim();
112176
- var CASBeacon = class extends Beacon {
112506
+ var CASBeacon = class extends SinglePartyBeacon {
112177
112507
  /**
112178
112508
  * Creates an instance of CASBeacon.
112179
112509
  * @param {BeaconService} service The service of the Beacon.
@@ -112233,7 +112563,7 @@ ${value2}`;
112233
112563
  * Creates a CAS Announcement mapping the DID to the update hash, broadcasts the hash of the
112234
112564
  * announcement via OP_RETURN, and optionally publishes the announcement off-chain via the
112235
112565
  * supplied `casPublish` callback. UTXO selection, PSBT construction, fee estimation, signing,
112236
- * and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
112566
+ * and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
112237
112567
  *
112238
112568
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112239
112569
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112261,7 +112591,7 @@ ${value2}`;
112261
112591
 
112262
112592
  // src/core/beacon/singleton-beacon.ts
112263
112593
  init_shim();
112264
- var SingletonBeacon = class extends Beacon {
112594
+ var SingletonBeacon = class extends SinglePartyBeacon {
112265
112595
  /**
112266
112596
  * Creates an instance of SingletonBeacon.
112267
112597
  * @param {BeaconService} service The BeaconService object representing the funded beacon to announce the update to.
@@ -112298,7 +112628,7 @@ ${value2}`;
112298
112628
  *
112299
112629
  * The signal bytes embedded in OP_RETURN are the SHA-256 canonical hash of the signed update.
112300
112630
  * UTXO selection, PSBT construction, fee estimation, signing, and broadcast are delegated to
112301
- * {@link Beacon.buildSignAndBroadcast}.
112631
+ * {@link SinglePartyBeacon.buildSignAndBroadcast}.
112302
112632
  *
112303
112633
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112304
112634
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112317,7 +112647,7 @@ ${value2}`;
112317
112647
  // src/core/beacon/smt-beacon.ts
112318
112648
  init_shim();
112319
112649
  init_utils();
112320
- var SMTBeacon = class extends Beacon {
112650
+ var SMTBeacon = class extends SinglePartyBeacon {
112321
112651
  /**
112322
112652
  * Creates an instance of SMTBeacon.
112323
112653
  * @param {BeaconService} service The Beacon service.
@@ -112393,7 +112723,7 @@ ${value2}`;
112393
112723
  * Builds a single-entry Sparse Merkle Tree from the signed update, then broadcasts the tree's
112394
112724
  * root hash via OP_RETURN. For multi-party aggregation, use the {@link AggregationService}
112395
112725
  * subsystem directly instead of this method. UTXO selection, PSBT construction, fee estimation,
112396
- * signing, and broadcast are delegated to {@link Beacon.buildSignAndBroadcast}.
112726
+ * signing, and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
112397
112727
  *
112398
112728
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
112399
112729
  * @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
@@ -112419,7 +112749,7 @@ ${value2}`;
112419
112749
  /**
112420
112750
  * Establish a Beacon instance based on the provided service and optional sidecar data.
112421
112751
  * @param {BeaconService} service The beacon service configuration.
112422
- * @returns {Beacon} The established Beacon instance.
112752
+ * @returns {SinglePartyBeacon} The established Beacon instance.
112423
112753
  */
112424
112754
  static establish(service) {
112425
112755
  switch (service.type) {
@@ -112441,84 +112771,6 @@ ${value2}`;
112441
112771
  // src/core/beacon/signal-discovery.ts
112442
112772
  init_shim();
112443
112773
 
112444
- // ../bitcoin/dist/esm/index.js
112445
- init_shim();
112446
-
112447
- // ../bitcoin/dist/esm/connection.js
112448
- init_shim();
112449
-
112450
- // ../bitcoin/dist/esm/client/rest/index.js
112451
- init_shim();
112452
-
112453
- // ../bitcoin/dist/esm/client/rest/address.js
112454
- init_shim();
112455
-
112456
- // ../bitcoin/dist/esm/client/rest/block.js
112457
- init_shim();
112458
-
112459
- // ../bitcoin/dist/esm/errors.js
112460
- init_shim();
112461
-
112462
- // ../bitcoin/dist/esm/client/rest/transaction.js
112463
- init_shim();
112464
-
112465
- // ../bitcoin/dist/esm/client/rest/protocol.js
112466
- init_shim();
112467
-
112468
- // ../bitcoin/dist/esm/client/http.js
112469
- init_shim();
112470
-
112471
- // ../bitcoin/dist/esm/client/rpc/index.js
112472
- init_shim();
112473
-
112474
- // ../bitcoin/dist/esm/client/rpc/json-rpc.js
112475
- init_shim();
112476
-
112477
- // ../bitcoin/dist/esm/client/utils.js
112478
- init_shim();
112479
-
112480
- // ../bitcoin/dist/esm/client/rpc/protocol.js
112481
- init_shim();
112482
-
112483
- // ../bitcoin/dist/esm/network.js
112484
- init_shim();
112485
- var REGTEST_NETWORK = {
112486
- bech32: "bcrt",
112487
- pubKeyHash: 111,
112488
- scriptHash: 196,
112489
- wif: 239
112490
- };
112491
- function getNetwork(network) {
112492
- switch (network) {
112493
- case "bitcoin":
112494
- return NETWORK;
112495
- case "testnet3":
112496
- case "testnet4":
112497
- case "signet":
112498
- case "mutinynet":
112499
- return TEST_NETWORK;
112500
- case "regtest":
112501
- return REGTEST_NETWORK;
112502
- default:
112503
- throw new Error(`Unknown network "${network}"`);
112504
- }
112505
- }
112506
-
112507
- // ../bitcoin/dist/esm/constants.js
112508
- init_shim();
112509
- var TXIN_WITNESS_COINBASE = "0000000000000000000000000000000000000000000000000000000000000000";
112510
- var GENESIS_TX_ID = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b";
112511
-
112512
- // ../bitcoin/dist/esm/types.js
112513
- init_shim();
112514
- var VerbosityLevel;
112515
- (function(VerbosityLevel2) {
112516
- VerbosityLevel2[VerbosityLevel2["hex"] = 0] = "hex";
112517
- VerbosityLevel2[VerbosityLevel2["json"] = 1] = "json";
112518
- VerbosityLevel2[VerbosityLevel2["jsonext"] = 2] = "jsonext";
112519
- VerbosityLevel2[VerbosityLevel2["jsonextprev"] = 3] = "jsonextprev";
112520
- })(VerbosityLevel || (VerbosityLevel = {}));
112521
-
112522
112774
  // src/core/beacon/utils.ts
112523
112775
  init_shim();
112524
112776