@did-btcr2/method 0.34.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 (46) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/browser.js +190 -112
  3. package/dist/browser.mjs +190 -112
  4. package/dist/cjs/index.js +130 -60
  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/participant-runner.js +9 -1
  10. package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
  11. package/dist/esm/core/aggregation/runner/service-runner.js +4 -1
  12. package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
  13. package/dist/esm/core/aggregation/service.js +4 -4
  14. package/dist/esm/core/aggregation/service.js.map +1 -1
  15. package/dist/esm/core/aggregation/signer.js +33 -0
  16. package/dist/esm/core/aggregation/signer.js.map +1 -0
  17. package/dist/esm/core/aggregation/signing-session.js +34 -11
  18. package/dist/esm/core/aggregation/signing-session.js.map +1 -1
  19. package/dist/esm/core/aggregation/transport/in-memory.js +5 -2
  20. package/dist/esm/core/aggregation/transport/in-memory.js.map +1 -1
  21. package/dist/esm/index.js +1 -0
  22. package/dist/esm/index.js.map +1 -1
  23. package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
  24. package/dist/types/core/aggregation/participant.d.ts +17 -4
  25. package/dist/types/core/aggregation/participant.d.ts.map +1 -1
  26. package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
  27. package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
  28. package/dist/types/core/aggregation/service.d.ts +10 -4
  29. package/dist/types/core/aggregation/service.d.ts.map +1 -1
  30. package/dist/types/core/aggregation/signer.d.ts +50 -0
  31. package/dist/types/core/aggregation/signer.d.ts.map +1 -0
  32. package/dist/types/core/aggregation/signing-session.d.ts +13 -5
  33. package/dist/types/core/aggregation/signing-session.d.ts.map +1 -1
  34. package/dist/types/core/aggregation/transport/in-memory.d.ts.map +1 -1
  35. package/dist/types/index.d.ts +1 -0
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/package.json +4 -4
  38. package/src/core/aggregation/cohort.ts +5 -1
  39. package/src/core/aggregation/participant.ts +38 -12
  40. package/src/core/aggregation/runner/participant-runner.ts +9 -1
  41. package/src/core/aggregation/runner/service-runner.ts +4 -1
  42. package/src/core/aggregation/service.ts +12 -6
  43. package/src/core/aggregation/signer.ts +67 -0
  44. package/src/core/aggregation/signing-session.ts +34 -11
  45. package/src/core/aggregation/transport/in-memory.ts +7 -3
  46. package/src/index.ts +1 -0
package/dist/cjs/index.js CHANGED
@@ -86,6 +86,7 @@ __export(index_exports, {
86
86
  InMemoryRateLimitStore: () => InMemoryRateLimitStore,
87
87
  InMemoryTransport: () => InMemoryTransport,
88
88
  InboxBuffer: () => InboxBuffer,
89
+ KeyPairAggregationSigner: () => KeyPairAggregationSigner,
89
90
  NONCE_CONTRIBUTION: () => NONCE_CONTRIBUTION,
90
91
  NonceCache: () => NonceCache,
91
92
  NostrTransport: () => NostrTransport,
@@ -224,6 +225,7 @@ function getBeaconStrategy(type) {
224
225
  }
225
226
 
226
227
  // src/core/aggregation/cohort.ts
228
+ var import_bitcoin = require("@did-btcr2/bitcoin");
227
229
  var import_common3 = require("@did-btcr2/common");
228
230
  var import_smt2 = require("@did-btcr2/smt");
229
231
  var import_secp256k1 = require("@noble/curves/secp256k1.js");
@@ -325,7 +327,7 @@ var AggregationCohort = class {
325
327
  }
326
328
  const keyAggContext = (0, import_musig2.keyAggregate)(this.#cohortKeys);
327
329
  const aggPubkey = (0, import_musig2.keyAggExport)(keyAggContext);
328
- 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));
329
331
  this.tapTweak = import_secp256k1.schnorr.utils.taggedHash("TapTweak", aggPubkey);
330
332
  if (!payment.address) {
331
333
  throw new AggregationCohortError(
@@ -596,6 +598,7 @@ var SigningSessionPhase = /* @__PURE__ */ ((SigningSessionPhase2) => {
596
598
  })(SigningSessionPhase || {});
597
599
 
598
600
  // src/core/aggregation/signing-session.ts
601
+ var import_keypair = require("@did-btcr2/keypair");
599
602
  var import_btc_signer2 = require("@scure/btc-signer");
600
603
  var musig2 = __toESM(require("@scure/btc-signer/musig2"), 1);
601
604
  var BeaconSigningSession = class {
@@ -619,8 +622,14 @@ var BeaconSigningSession = class {
619
622
  signature;
620
623
  /** Current signing session phase. */
621
624
  phase;
622
- /** Participant's secret nonce (held only by the participant during signing). */
623
- 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;
624
633
  constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }) {
625
634
  this.id = id || crypto.randomUUID();
626
635
  this.cohort = cohort;
@@ -772,22 +781,24 @@ var BeaconSigningSession = class {
772
781
  generateNonceContribution(participantPublicKey, participantSecretKey) {
773
782
  const aggPublicKey = musig2.keyAggExport(musig2.keyAggregate(this.cohort.cohortKeys));
774
783
  const nonces = musig2.nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
775
- this.secretNonce = nonces.secret;
784
+ this.#secretNonce = nonces.secret;
776
785
  return nonces.public;
777
786
  }
778
787
  /**
779
788
  * Generates a partial signature using the participant's secret key + secret nonce.
780
789
  * Requires the aggregated nonce to have been set first (via the service).
781
790
  *
782
- * Zeros the stored `secretNonce` after use. JS cannot truly erase memory (GC
783
- * and immutable strings), but overwriting the bytes shortens the exposure
784
- * 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.
785
796
  */
786
797
  generatePartialSignature(participantSecretKey) {
787
798
  if (!this.aggregatedNonce) {
788
799
  throw new SigningSessionError("Aggregated nonce not available.", "MISSING_AGGREGATED_NONCE");
789
800
  }
790
- if (!this.secretNonce) {
801
+ if (!this.#secretNonce) {
791
802
  throw new SigningSessionError("Secret nonce not available \u2014 generateNonceContribution() must be called first.", "MISSING_SECRET_NONCE");
792
803
  }
793
804
  const session = new musig2.Session(
@@ -797,10 +808,23 @@ var BeaconSigningSession = class {
797
808
  [this.cohort.tapTweak],
798
809
  [true]
799
810
  );
800
- const partialSig = session.sign(this.secretNonce, participantSecretKey);
801
- this.secretNonce.fill(0);
802
- this.secretNonce = void 0;
803
- 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
+ }
804
828
  }
805
829
  isComplete() {
806
830
  return this.phase === "Complete" /* Complete */;
@@ -814,13 +838,13 @@ var BeaconSigningSession = class {
814
838
  var DEFAULT_MAX_UPDATE_SIZE_BYTES = 256 * 1024;
815
839
  var AggregationService = class {
816
840
  did;
817
- keys;
841
+ publicKey;
818
842
  maxUpdateSizeBytes;
819
843
  /** Per-cohort state, keyed by cohortId. */
820
844
  #cohortStates = /* @__PURE__ */ new Map();
821
- constructor({ did, keys, maxUpdateSizeBytes }) {
845
+ constructor({ did, publicKey, maxUpdateSizeBytes }) {
822
846
  this.did = did;
823
- this.keys = keys;
847
+ this.publicKey = publicKey;
824
848
  this.maxUpdateSizeBytes = maxUpdateSizeBytes ?? DEFAULT_MAX_UPDATE_SIZE_BYTES;
825
849
  }
826
850
  receive(message) {
@@ -913,7 +937,7 @@ var AggregationService = class {
913
937
  cohortSize: state.config.minParticipants,
914
938
  beaconType: state.config.beaconType,
915
939
  network: state.config.network,
916
- communicationPk: this.keys.publicKey.compressed
940
+ communicationPk: this.publicKey.compressed
917
941
  });
918
942
  state.phase = "Advertised" /* Advertised */;
919
943
  return [message];
@@ -1325,12 +1349,17 @@ var import_utils3 = require("@noble/hashes/utils");
1325
1349
  var import_btc_signer3 = require("@scure/btc-signer");
1326
1350
  var AggregationParticipant = class {
1327
1351
  did;
1328
- keys;
1352
+ /** MuSig2 signing capability. The raw secret never lives as a field here. */
1353
+ #signer;
1329
1354
  /** Per-cohort state, keyed by cohortId. */
1330
1355
  #cohortStates = /* @__PURE__ */ new Map();
1331
- constructor({ did, keys }) {
1356
+ constructor({ did, signer }) {
1332
1357
  this.did = did;
1333
- 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;
1334
1363
  }
1335
1364
  /**
1336
1365
  * Process an incoming message. Updates internal state but never produces
@@ -1419,8 +1448,8 @@ var AggregationParticipant = class {
1419
1448
  from: this.did,
1420
1449
  to: state.serviceDid,
1421
1450
  cohortId,
1422
- participantPk: this.keys.publicKey.compressed,
1423
- communicationPk: this.keys.publicKey.compressed
1451
+ participantPk: this.publicKey,
1452
+ communicationPk: this.publicKey
1424
1453
  });
1425
1454
  return [optInMessage];
1426
1455
  }
@@ -1451,7 +1480,7 @@ var AggregationParticipant = class {
1451
1480
  const beaconAddress = message.body?.beaconAddress;
1452
1481
  const cohortKeys = message.body?.cohortKeys;
1453
1482
  if (!beaconAddress || !cohortKeys) return;
1454
- const participantPkHex = (0, import_utils3.bytesToHex)(this.keys.publicKey.compressed);
1483
+ const participantPkHex = (0, import_utils3.bytesToHex)(this.publicKey);
1455
1484
  const cohortKeysHex = cohortKeys.map((k) => (0, import_utils3.bytesToHex)(new Uint8Array(k)));
1456
1485
  state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
1457
1486
  state.phase = "CohortReady" /* CohortReady */;
@@ -1618,9 +1647,8 @@ var AggregationParticipant = class {
1618
1647
  prevOutValues
1619
1648
  });
1620
1649
  state.signingSession = session;
1621
- const nonceContribution = session.generateNonceContribution(
1622
- this.keys.publicKey.compressed,
1623
- this.keys.secretKey.bytes
1650
+ const nonceContribution = this.#signer.withSecret(
1651
+ (secretKey) => session.generateNonceContribution(this.publicKey, secretKey)
1624
1652
  );
1625
1653
  state.phase = "NonceSent" /* NonceSent */;
1626
1654
  return [createNonceContributionMessage({
@@ -1663,7 +1691,10 @@ var AggregationParticipant = class {
1663
1691
  { cohortId }
1664
1692
  );
1665
1693
  }
1666
- 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
+ );
1667
1698
  state.phase = "Complete" /* Complete */;
1668
1699
  return [createSignatureAuthorizationMessage({
1669
1700
  from: this.did,
@@ -1676,6 +1707,37 @@ var AggregationParticipant = class {
1676
1707
  getCohortPhase(cohortId) {
1677
1708
  return this.#cohortStates.get(cohortId)?.phase;
1678
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
+ }
1679
1741
  };
1680
1742
 
1681
1743
  // src/core/aggregation/logger.ts
@@ -1787,11 +1849,11 @@ var TransportAdapterError = class extends import_common6.MethodError {
1787
1849
  var import_common10 = require("@did-btcr2/common");
1788
1850
 
1789
1851
  // src/core/aggregation/transport/http/client.ts
1790
- var import_keypair2 = require("@did-btcr2/keypair");
1852
+ var import_keypair4 = require("@did-btcr2/keypair");
1791
1853
 
1792
1854
  // src/core/identifier.ts
1793
1855
  var import_common7 = require("@did-btcr2/common");
1794
- var import_keypair = require("@did-btcr2/keypair");
1856
+ var import_keypair3 = require("@did-btcr2/keypair");
1795
1857
  var import_base4 = require("@scure/base");
1796
1858
  var Identifier = class _Identifier {
1797
1859
  /**
@@ -1824,7 +1886,7 @@ var Identifier = class _Identifier {
1824
1886
  }
1825
1887
  if (idType === "KEY") {
1826
1888
  try {
1827
- new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
1889
+ new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1828
1890
  } catch {
1829
1891
  throw new import_common7.IdentifierError(
1830
1892
  'Expected "genesisBytes" to be a valid compressed secp256k1 public key',
@@ -1926,7 +1988,7 @@ var Identifier = class _Identifier {
1926
1988
  const genesisBytes = dataBytes.slice(byteIndex + 1);
1927
1989
  if (idType === "KEY") {
1928
1990
  try {
1929
- new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
1991
+ new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1930
1992
  } catch {
1931
1993
  throw new import_common7.IdentifierError(`Invalid genesisBytes: ${genesisBytes}`, import_common7.INVALID_DID, { identifier });
1932
1994
  }
@@ -1938,7 +2000,7 @@ var Identifier = class _Identifier {
1938
2000
  * @returns {string} The new did:btcr2 identifier.
1939
2001
  */
1940
2002
  static generate() {
1941
- const keyPair = import_keypair.SchnorrKeyPair.generate();
2003
+ const keyPair = import_keypair3.SchnorrKeyPair.generate();
1942
2004
  const did = this.encode(
1943
2005
  keyPair.publicKey.compressed,
1944
2006
  {
@@ -1964,7 +2026,7 @@ var Identifier = class _Identifier {
1964
2026
  { did, idType }
1965
2027
  );
1966
2028
  }
1967
- return new import_keypair.CompressedSecp256k1PublicKey(genesisBytes);
2029
+ return new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
1968
2030
  }
1969
2031
  /**
1970
2032
  * Validates a did:btcr2 identifier.
@@ -2371,7 +2433,7 @@ var HttpClientTransport = class {
2371
2433
  }
2372
2434
  registerPeer(did, communicationPk) {
2373
2435
  try {
2374
- new import_keypair2.CompressedSecp256k1PublicKey(communicationPk);
2436
+ new import_keypair4.CompressedSecp256k1PublicKey(communicationPk);
2375
2437
  } catch {
2376
2438
  throw new HttpTransportError(
2377
2439
  `Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
@@ -2567,14 +2629,14 @@ var HttpClientTransport = class {
2567
2629
  const peerBytes = this.#peers.get(did);
2568
2630
  if (peerBytes) {
2569
2631
  try {
2570
- return new import_keypair2.CompressedSecp256k1PublicKey(peerBytes);
2632
+ return new import_keypair4.CompressedSecp256k1PublicKey(peerBytes);
2571
2633
  } catch {
2572
2634
  }
2573
2635
  }
2574
2636
  try {
2575
2637
  const components = Identifier.decode(did);
2576
2638
  if (components.idType === "KEY") {
2577
- return new import_keypair2.CompressedSecp256k1PublicKey(components.genesisBytes);
2639
+ return new import_keypair4.CompressedSecp256k1PublicKey(components.genesisBytes);
2578
2640
  }
2579
2641
  } catch {
2580
2642
  }
@@ -2619,7 +2681,7 @@ function flattenMessage(msg) {
2619
2681
  }
2620
2682
 
2621
2683
  // src/core/aggregation/transport/http/server.ts
2622
- var import_keypair3 = require("@did-btcr2/keypair");
2684
+ var import_keypair5 = require("@did-btcr2/keypair");
2623
2685
 
2624
2686
  // src/core/aggregation/transport/http/inbox-buffer.ts
2625
2687
  var InboxBuffer = class {
@@ -2784,7 +2846,7 @@ var HttpServerTransport = class {
2784
2846
  }
2785
2847
  registerPeer(did, communicationPk) {
2786
2848
  try {
2787
- new import_keypair3.CompressedSecp256k1PublicKey(communicationPk);
2849
+ new import_keypair5.CompressedSecp256k1PublicKey(communicationPk);
2788
2850
  } catch {
2789
2851
  throw new HttpTransportError(
2790
2852
  `Invalid peer public key for ${did}`,
@@ -3062,14 +3124,14 @@ var HttpServerTransport = class {
3062
3124
  const peerBytes = this.#peers.get(did);
3063
3125
  if (peerBytes) {
3064
3126
  try {
3065
- return new import_keypair3.CompressedSecp256k1PublicKey(peerBytes);
3127
+ return new import_keypair5.CompressedSecp256k1PublicKey(peerBytes);
3066
3128
  } catch {
3067
3129
  }
3068
3130
  }
3069
3131
  try {
3070
3132
  const components = Identifier.decode(did);
3071
3133
  if (components.idType === "KEY") {
3072
- return new import_keypair3.CompressedSecp256k1PublicKey(components.genesisBytes);
3134
+ return new import_keypair5.CompressedSecp256k1PublicKey(components.genesisBytes);
3073
3135
  }
3074
3136
  } catch {
3075
3137
  }
@@ -3168,7 +3230,7 @@ function flattenMessage2(msg) {
3168
3230
  }
3169
3231
 
3170
3232
  // src/core/aggregation/transport/nostr.ts
3171
- var import_keypair4 = require("@did-btcr2/keypair");
3233
+ var import_keypair6 = require("@did-btcr2/keypair");
3172
3234
  var import_utils6 = require("@noble/hashes/utils");
3173
3235
  var import_nostr_tools = require("nostr-tools");
3174
3236
  var import_pool = require("nostr-tools/pool");
@@ -3266,7 +3328,7 @@ var NostrTransport = class _NostrTransport {
3266
3328
  */
3267
3329
  registerPeer(did, communicationPk) {
3268
3330
  try {
3269
- new import_keypair4.CompressedSecp256k1PublicKey(communicationPk);
3331
+ new import_keypair6.CompressedSecp256k1PublicKey(communicationPk);
3270
3332
  } catch {
3271
3333
  throw new TransportAdapterError(
3272
3334
  `Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
@@ -3373,7 +3435,7 @@ var NostrTransport = class _NostrTransport {
3373
3435
  if (to) {
3374
3436
  const recipientPkBytes = this.#peerRegistry.get(to);
3375
3437
  if (recipientPkBytes) {
3376
- const recipientPk = new import_keypair4.CompressedSecp256k1PublicKey(recipientPkBytes);
3438
+ const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
3377
3439
  tags.push(["p", (0, import_utils6.bytesToHex)(recipientPk.x)]);
3378
3440
  }
3379
3441
  }
@@ -3404,7 +3466,7 @@ var NostrTransport = class _NostrTransport {
3404
3466
  { adapter: this.name, did: to }
3405
3467
  );
3406
3468
  }
3407
- const recipientPk = new import_keypair4.CompressedSecp256k1PublicKey(recipientPkBytes);
3469
+ const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
3408
3470
  const conversationKey = import_nostr_tools.nip44.v2.utils.getConversationKey(
3409
3471
  senderKeys.secretKey.bytes,
3410
3472
  (0, import_utils6.bytesToHex)(recipientPk.x)
@@ -3695,10 +3757,10 @@ var InMemoryTransport = class {
3695
3757
  start() {
3696
3758
  }
3697
3759
  registerActor(did, keys) {
3698
- this.#actors.set(did, { keys, handlers: /* @__PURE__ */ new Map() });
3760
+ this.#actors.set(did, { publicKey: keys.publicKey.compressed, handlers: /* @__PURE__ */ new Map() });
3699
3761
  }
3700
3762
  getActorPk(did) {
3701
- return this.#actors.get(did)?.keys.publicKey.compressed;
3763
+ return this.#actors.get(did)?.publicKey;
3702
3764
  }
3703
3765
  /** True if `did` is registered on this transport. Used by the bus for routing. */
3704
3766
  hasActor(did) {
@@ -3909,8 +3971,11 @@ var AggregationServiceRunner = class _AggregationServiceRunner extends TypedEven
3909
3971
  this.#phaseTimeoutMs = options.phaseTimeoutMs;
3910
3972
  this.#advertRepeatIntervalMs = options.advertRepeatIntervalMs ?? DEFAULT_ADVERT_REPEAT_INTERVAL_MS;
3911
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.
3912
3977
  did: options.did,
3913
- keys: options.keys,
3978
+ publicKey: options.keys.publicKey,
3914
3979
  maxUpdateSizeBytes: options.maxUpdateSizeBytes
3915
3980
  });
3916
3981
  }
@@ -4262,7 +4327,10 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
4262
4327
  this.#onProvideUpdate = options.onProvideUpdate;
4263
4328
  this.#onValidateData = options.onValidateData ?? (async (info) => ({ approved: info.matches }));
4264
4329
  this.#onApproveSigning = options.onApproveSigning ?? (async () => ({ approved: true }));
4265
- 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
+ });
4266
4334
  }
4267
4335
  /**
4268
4336
  * Start listening for cohorts. The runner stays active until {@link stop}
@@ -4275,6 +4343,7 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
4275
4343
  stop() {
4276
4344
  this.#stopped = true;
4277
4345
  this.#unregisterHandlers();
4346
+ this.session.clearSecrets();
4278
4347
  }
4279
4348
  /** Message types this runner listens for on the transport. */
4280
4349
  static #HANDLED_MESSAGE_TYPES = [
@@ -5110,11 +5179,11 @@ var BeaconFactory = class {
5110
5179
  };
5111
5180
 
5112
5181
  // src/core/beacon/signal-discovery.ts
5113
- var import_bitcoin2 = require("@did-btcr2/bitcoin");
5182
+ var import_bitcoin3 = require("@did-btcr2/bitcoin");
5114
5183
  var import_common18 = require("@did-btcr2/common");
5115
5184
 
5116
5185
  // src/core/beacon/utils.ts
5117
- var import_bitcoin = require("@did-btcr2/bitcoin");
5186
+ var import_bitcoin2 = require("@did-btcr2/bitcoin");
5118
5187
  var import_common17 = require("@did-btcr2/common");
5119
5188
  var import_btc_signer5 = require("@scure/btc-signer");
5120
5189
 
@@ -6221,7 +6290,7 @@ var BeaconUtils = class {
6221
6290
  static createBeaconService(did, addressType, beaconType) {
6222
6291
  try {
6223
6292
  const components = Identifier.decode(did);
6224
- const network = (0, import_bitcoin.getNetwork)(components.network);
6293
+ const network = (0, import_bitcoin2.getNetwork)(components.network);
6225
6294
  const pubkey = components.genesisBytes;
6226
6295
  const id = `${did}#initial${addressType.toUpperCase()}`;
6227
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;
@@ -6372,14 +6441,14 @@ var BeaconSignalDiscovery = class {
6372
6441
  console.info(`Searching for beacon signals, please wait ...`);
6373
6442
  while (block.height <= targetHeight) {
6374
6443
  for (const tx of block.tx) {
6375
- if (tx.txid === import_bitcoin2.GENESIS_TX_ID) {
6444
+ if (tx.txid === import_bitcoin3.GENESIS_TX_ID) {
6376
6445
  continue;
6377
6446
  }
6378
6447
  for (const vin of tx.vin) {
6379
6448
  if (vin.coinbase) {
6380
6449
  continue;
6381
6450
  }
6382
- 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) {
6383
6452
  continue;
6384
6453
  }
6385
6454
  if (!vin.txid) {
@@ -6433,10 +6502,10 @@ var BeaconSignalDiscovery = class {
6433
6502
  };
6434
6503
 
6435
6504
  // src/core/resolver.ts
6436
- var import_bitcoin4 = require("@did-btcr2/bitcoin");
6505
+ var import_bitcoin5 = require("@did-btcr2/bitcoin");
6437
6506
  var import_common22 = require("@did-btcr2/common");
6438
6507
  var import_cryptosuite3 = require("@did-btcr2/cryptosuite");
6439
- var import_keypair6 = require("@did-btcr2/keypair");
6508
+ var import_keypair8 = require("@did-btcr2/keypair");
6440
6509
 
6441
6510
  // src/did-btcr2.ts
6442
6511
  var import_common21 = require("@did-btcr2/common");
@@ -6447,9 +6516,9 @@ var import_common20 = require("@did-btcr2/common");
6447
6516
  var import_cryptosuite2 = require("@did-btcr2/cryptosuite");
6448
6517
 
6449
6518
  // src/utils/did-document.ts
6450
- var import_bitcoin3 = require("@did-btcr2/bitcoin");
6519
+ var import_bitcoin4 = require("@did-btcr2/bitcoin");
6451
6520
  var import_common19 = require("@did-btcr2/common");
6452
- var import_keypair5 = require("@did-btcr2/keypair");
6521
+ var import_keypair7 = require("@did-btcr2/keypair");
6453
6522
  var import_utils11 = require("@web5/dids/utils");
6454
6523
  var import_btc_signer6 = require("@scure/btc-signer");
6455
6524
  var BTCR2_DID_DOCUMENT_CONTEXT = [
@@ -6771,9 +6840,9 @@ var GenesisDocument = class _GenesisDocument extends DidDocument {
6771
6840
  * @returns {GenesisDocument} A new GenesisDocument with the placeholder ID.
6772
6841
  */
6773
6842
  static fromPublicKey(publicKey, network) {
6774
- const pk = new import_keypair5.CompressedSecp256k1PublicKey(publicKey);
6843
+ const pk = new import_keypair7.CompressedSecp256k1PublicKey(publicKey);
6775
6844
  const id = ID_PLACEHOLDER_VALUE;
6776
- 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;
6777
6846
  const services = [{
6778
6847
  id: `${id}#service-0`,
6779
6848
  serviceEndpoint: `bitcoin:${address}`,
@@ -7280,11 +7349,11 @@ var Resolver = class _Resolver {
7280
7349
  static deterministic(didComponents) {
7281
7350
  const genesisBytes = didComponents.genesisBytes;
7282
7351
  const did = Identifier.encode(genesisBytes, didComponents);
7283
- const { multibase } = new import_keypair6.CompressedSecp256k1PublicKey(genesisBytes);
7352
+ const { multibase } = new import_keypair8.CompressedSecp256k1PublicKey(genesisBytes);
7284
7353
  const service = BeaconUtils.generateBeaconServices({
7285
7354
  id: did,
7286
7355
  publicKey: genesisBytes,
7287
- network: (0, import_bitcoin4.getNetwork)(didComponents.network),
7356
+ network: (0, import_bitcoin5.getNetwork)(didComponents.network),
7288
7357
  beaconType: "SingletonBeacon"
7289
7358
  });
7290
7359
  return new DidDocument({
@@ -7757,6 +7826,7 @@ var DidDocumentBuilder = class {
7757
7826
  InMemoryRateLimitStore,
7758
7827
  InMemoryTransport,
7759
7828
  InboxBuffer,
7829
+ KeyPairAggregationSigner,
7760
7830
  NONCE_CONTRIBUTION,
7761
7831
  NonceCache,
7762
7832
  NostrTransport,
@@ -1,3 +1,4 @@
1
+ import { getNetwork } from '@did-btcr2/bitcoin';
1
2
  import { canonicalHash, canonicalize, hash } from '@did-btcr2/common';
2
3
  import { BTCR2MerkleTree } from '@did-btcr2/smt';
3
4
  import { schnorr } from '@noble/curves/secp256k1.js';
@@ -84,7 +85,10 @@ export class AggregationCohort {
84
85
  }
85
86
  const keyAggContext = keyAggregate(this.#cohortKeys);
86
87
  const aggPubkey = keyAggExport(keyAggContext);
87
- const payment = p2tr(aggPubkey);
88
+ // Derive the address for the cohort's network. Without the network arg
89
+ // p2tr defaults to mainnet, so a mutinynet/signet/regtest cohort would
90
+ // otherwise advertise a `bc1p...` address that no participant can fund.
91
+ const payment = p2tr(aggPubkey, undefined, getNetwork(this.network));
88
92
  // BIP-341: key-path-only P2TR has no script tree. Compute the tweak:
89
93
  // taggedHash("TapTweak", internalPubkey).
90
94
  this.tapTweak = schnorr.utils.taggedHash('TapTweak', aggPubkey);
@@ -1 +1 @@
1
- {"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../../../src/core/aggregation/cohort.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../../../src/core/aggregation/cohort.ts"],"names":[],"mappings":"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"}
@@ -21,12 +21,17 @@ import { BeaconSigningSession } from './signing-session.js';
21
21
  */
22
22
  export class AggregationParticipant {
23
23
  did;
24
- keys;
24
+ /** MuSig2 signing capability. The raw secret never lives as a field here. */
25
+ #signer;
25
26
  /** Per-cohort state, keyed by cohortId. */
26
27
  #cohortStates = new Map();
27
- constructor({ did, keys }) {
28
+ constructor({ did, signer }) {
28
29
  this.did = did;
29
- this.keys = keys;
30
+ this.#signer = signer;
31
+ }
32
+ /** The participant's compressed (33-byte) MuSig2 public key. Not secret. */
33
+ get publicKey() {
34
+ return this.#signer.publicKey;
30
35
  }
31
36
  /**
32
37
  * Process an incoming message. Updates internal state but never produces
@@ -116,8 +121,8 @@ export class AggregationParticipant {
116
121
  from: this.did,
117
122
  to: state.serviceDid,
118
123
  cohortId,
119
- participantPk: this.keys.publicKey.compressed,
120
- communicationPk: this.keys.publicKey.compressed,
124
+ participantPk: this.publicKey,
125
+ communicationPk: this.publicKey,
121
126
  });
122
127
  return [optInMessage];
123
128
  }
@@ -153,7 +158,7 @@ export class AggregationParticipant {
153
158
  const cohortKeys = message.body?.cohortKeys;
154
159
  if (!beaconAddress || !cohortKeys)
155
160
  return;
156
- const participantPkHex = bytesToHex(this.keys.publicKey.compressed);
161
+ const participantPkHex = bytesToHex(this.publicKey);
157
162
  const cohortKeysHex = cohortKeys.map(k => bytesToHex(new Uint8Array(k)));
158
163
  state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
159
164
  state.phase = ParticipantCohortPhase.CohortReady;
@@ -314,7 +319,7 @@ export class AggregationParticipant {
314
319
  prevOutValues,
315
320
  });
316
321
  state.signingSession = session;
317
- const nonceContribution = session.generateNonceContribution(this.keys.publicKey.compressed, this.keys.secretKey.bytes);
322
+ const nonceContribution = this.#signer.withSecret(secretKey => session.generateNonceContribution(this.publicKey, secretKey));
318
323
  state.phase = ParticipantCohortPhase.NonceSent;
319
324
  return [createNonceContributionMessage({
320
325
  from: this.did,
@@ -352,7 +357,8 @@ export class AggregationParticipant {
352
357
  if (!state.signingSession) {
353
358
  throw new AggregationParticipantError(`No signing session for cohort ${cohortId}.`, 'MISSING_STATE', { cohortId });
354
359
  }
355
- const partialSig = state.signingSession.generatePartialSignature(this.keys.secretKey.bytes);
360
+ const signingSession = state.signingSession;
361
+ const partialSig = this.#signer.withSecret(secretKey => signingSession.generatePartialSignature(secretKey));
356
362
  state.phase = ParticipantCohortPhase.Complete;
357
363
  return [createSignatureAuthorizationMessage({
358
364
  from: this.did,
@@ -365,5 +371,16 @@ export class AggregationParticipant {
365
371
  getCohortPhase(cohortId) {
366
372
  return this.#cohortStates.get(cohortId)?.phase;
367
373
  }
374
+ /**
375
+ * Zeroize any retained MuSig2 secret nonces across all cohorts. The raw
376
+ * signing key is never held here (it lives behind the {@link AggregationSigner}
377
+ * and is wiped per-operation), but an abandoned signing session can still hold
378
+ * a secret nonce; call this on teardown to clear it deterministically.
379
+ */
380
+ clearSecrets() {
381
+ for (const state of this.#cohortStates.values()) {
382
+ state.signingSession?.clearSecrets();
383
+ }
384
+ }
368
385
  }
369
386
  //# sourceMappingURL=participant.js.map