@did-btcr2/method 0.36.1 → 0.37.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 (164) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/browser.js +1060 -96
  3. package/dist/browser.mjs +1060 -96
  4. package/dist/cjs/index.js +1153 -179
  5. package/dist/esm/core/aggregation/beacon-strategy.js +19 -6
  6. package/dist/esm/core/aggregation/beacon-strategy.js.map +1 -1
  7. package/dist/esm/core/aggregation/cohort.js +142 -33
  8. package/dist/esm/core/aggregation/cohort.js.map +1 -1
  9. package/dist/esm/core/aggregation/conditions.js +27 -0
  10. package/dist/esm/core/aggregation/conditions.js.map +1 -1
  11. package/dist/esm/core/aggregation/fallback-spend.js +132 -0
  12. package/dist/esm/core/aggregation/fallback-spend.js.map +1 -0
  13. package/dist/esm/core/aggregation/messages/base.js.map +1 -1
  14. package/dist/esm/core/aggregation/messages/bodies.js +46 -1
  15. package/dist/esm/core/aggregation/messages/bodies.js.map +1 -1
  16. package/dist/esm/core/aggregation/messages/constants.js +11 -0
  17. package/dist/esm/core/aggregation/messages/constants.js.map +1 -1
  18. package/dist/esm/core/aggregation/messages/factories.js +27 -1
  19. package/dist/esm/core/aggregation/messages/factories.js.map +1 -1
  20. package/dist/esm/core/aggregation/messages/guards.js +4 -1
  21. package/dist/esm/core/aggregation/messages/guards.js.map +1 -1
  22. package/dist/esm/core/aggregation/participant.js +210 -21
  23. package/dist/esm/core/aggregation/participant.js.map +1 -1
  24. package/dist/esm/core/aggregation/phases.js +6 -0
  25. package/dist/esm/core/aggregation/phases.js.map +1 -1
  26. package/dist/esm/core/aggregation/recovery-policy.js +156 -0
  27. package/dist/esm/core/aggregation/recovery-policy.js.map +1 -0
  28. package/dist/esm/core/aggregation/recovery-spend.js +106 -0
  29. package/dist/esm/core/aggregation/recovery-spend.js.map +1 -0
  30. package/dist/esm/core/aggregation/runner/aggregation-runner.js +11 -3
  31. package/dist/esm/core/aggregation/runner/aggregation-runner.js.map +1 -1
  32. package/dist/esm/core/aggregation/runner/participant-runner.js +74 -22
  33. package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
  34. package/dist/esm/core/aggregation/runner/service-runner.js +97 -9
  35. package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
  36. package/dist/esm/core/aggregation/service.js +221 -11
  37. package/dist/esm/core/aggregation/service.js.map +1 -1
  38. package/dist/esm/core/aggregation/signing-session.js +3 -3
  39. package/dist/esm/core/aggregation/signing-session.js.map +1 -1
  40. package/dist/esm/core/aggregation/transport/http/envelope.js +3 -3
  41. package/dist/esm/core/aggregation/transport/http/inbox-buffer.js +1 -1
  42. package/dist/esm/core/aggregation/transport/http/nonce-cache.js +1 -1
  43. package/dist/esm/core/aggregation/transport/http/rate-limiter.js +1 -1
  44. package/dist/esm/core/aggregation/transport/http/request-auth.js +1 -1
  45. package/dist/esm/core/aggregation/transport/http/server.js +1 -1
  46. package/dist/esm/core/aggregation/transport/http/sse-stream.js +1 -1
  47. package/dist/esm/core/aggregation/transport/http/sse-writer.js +1 -1
  48. package/dist/esm/core/aggregation/transport/in-memory.js +1 -1
  49. package/dist/esm/core/aggregation/transport/nostr.js +6 -6
  50. package/dist/esm/core/beacon/beacon.js +15 -10
  51. package/dist/esm/core/beacon/beacon.js.map +1 -1
  52. package/dist/esm/core/beacon/cas-beacon.js +6 -6
  53. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  54. package/dist/esm/core/beacon/singleton-beacon.js +2 -2
  55. package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
  56. package/dist/esm/core/beacon/smt-beacon.js +3 -3
  57. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  58. package/dist/esm/core/resolver.js +8 -8
  59. package/dist/esm/core/resolver.js.map +1 -1
  60. package/dist/esm/core/updater.js +6 -6
  61. package/dist/esm/core/updater.js.map +1 -1
  62. package/dist/esm/did-btcr2.js +2 -2
  63. package/dist/esm/index.js +3 -0
  64. package/dist/esm/index.js.map +1 -1
  65. package/dist/types/core/aggregation/beacon-strategy.d.ts +8 -4
  66. package/dist/types/core/aggregation/beacon-strategy.d.ts.map +1 -1
  67. package/dist/types/core/aggregation/cohort.d.ts +88 -17
  68. package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
  69. package/dist/types/core/aggregation/conditions.d.ts +28 -0
  70. package/dist/types/core/aggregation/conditions.d.ts.map +1 -1
  71. package/dist/types/core/aggregation/fallback-spend.d.ts +94 -0
  72. package/dist/types/core/aggregation/fallback-spend.d.ts.map +1 -0
  73. package/dist/types/core/aggregation/logger.d.ts +1 -1
  74. package/dist/types/core/aggregation/messages/base.d.ts +6 -0
  75. package/dist/types/core/aggregation/messages/base.d.ts.map +1 -1
  76. package/dist/types/core/aggregation/messages/bodies.d.ts +50 -2
  77. package/dist/types/core/aggregation/messages/bodies.d.ts.map +1 -1
  78. package/dist/types/core/aggregation/messages/constants.d.ts +8 -0
  79. package/dist/types/core/aggregation/messages/constants.d.ts.map +1 -1
  80. package/dist/types/core/aggregation/messages/factories.d.ts +40 -0
  81. package/dist/types/core/aggregation/messages/factories.d.ts.map +1 -1
  82. package/dist/types/core/aggregation/messages/guards.d.ts.map +1 -1
  83. package/dist/types/core/aggregation/participant.d.ts +41 -7
  84. package/dist/types/core/aggregation/participant.d.ts.map +1 -1
  85. package/dist/types/core/aggregation/phases.d.ts +8 -2
  86. package/dist/types/core/aggregation/phases.d.ts.map +1 -1
  87. package/dist/types/core/aggregation/recovery-policy.d.ts +132 -0
  88. package/dist/types/core/aggregation/recovery-policy.d.ts.map +1 -0
  89. package/dist/types/core/aggregation/recovery-spend.d.ts +94 -0
  90. package/dist/types/core/aggregation/recovery-spend.d.ts.map +1 -0
  91. package/dist/types/core/aggregation/runner/aggregation-runner.d.ts +13 -3
  92. package/dist/types/core/aggregation/runner/aggregation-runner.d.ts.map +1 -1
  93. package/dist/types/core/aggregation/runner/events.d.ts +28 -7
  94. package/dist/types/core/aggregation/runner/events.d.ts.map +1 -1
  95. package/dist/types/core/aggregation/runner/participant-runner.d.ts +3 -3
  96. package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
  97. package/dist/types/core/aggregation/runner/service-runner.d.ts +28 -3
  98. package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
  99. package/dist/types/core/aggregation/service.d.ts +26 -2
  100. package/dist/types/core/aggregation/service.d.ts.map +1 -1
  101. package/dist/types/core/aggregation/signing-session.d.ts +2 -2
  102. package/dist/types/core/aggregation/signing-session.d.ts.map +1 -1
  103. package/dist/types/core/aggregation/transport/http/envelope.d.ts +3 -3
  104. package/dist/types/core/aggregation/transport/http/inbox-buffer.d.ts +1 -1
  105. package/dist/types/core/aggregation/transport/http/nonce-cache.d.ts +1 -1
  106. package/dist/types/core/aggregation/transport/http/rate-limiter.d.ts +1 -1
  107. package/dist/types/core/aggregation/transport/http/request-auth.d.ts +1 -1
  108. package/dist/types/core/aggregation/transport/http/server.d.ts +1 -1
  109. package/dist/types/core/aggregation/transport/http/sse-stream.d.ts +2 -2
  110. package/dist/types/core/aggregation/transport/http/sse-writer.d.ts +1 -1
  111. package/dist/types/core/aggregation/transport/in-memory.d.ts +1 -1
  112. package/dist/types/core/aggregation/transport/nostr.d.ts +4 -4
  113. package/dist/types/core/aggregation/transport/transport.d.ts +4 -4
  114. package/dist/types/core/aggregation/transport/transport.d.ts.map +1 -1
  115. package/dist/types/core/beacon/beacon.d.ts +7 -7
  116. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  117. package/dist/types/core/beacon/cas-beacon.d.ts +2 -2
  118. package/dist/types/core/beacon/interfaces.d.ts +1 -1
  119. package/dist/types/core/resolver.d.ts +3 -3
  120. package/dist/types/core/updater.d.ts +4 -4
  121. package/dist/types/did-btcr2.d.ts +2 -2
  122. package/dist/types/index.d.ts +3 -0
  123. package/dist/types/index.d.ts.map +1 -1
  124. package/package.json +4 -4
  125. package/src/core/aggregation/beacon-strategy.ts +27 -9
  126. package/src/core/aggregation/cohort.ts +171 -35
  127. package/src/core/aggregation/conditions.ts +56 -0
  128. package/src/core/aggregation/fallback-spend.ts +223 -0
  129. package/src/core/aggregation/logger.ts +1 -1
  130. package/src/core/aggregation/messages/base.ts +6 -0
  131. package/src/core/aggregation/messages/bodies.ts +94 -1
  132. package/src/core/aggregation/messages/constants.ts +12 -0
  133. package/src/core/aggregation/messages/factories.ts +57 -0
  134. package/src/core/aggregation/messages/guards.ts +6 -0
  135. package/src/core/aggregation/participant.ts +255 -23
  136. package/src/core/aggregation/phases.ts +9 -0
  137. package/src/core/aggregation/recovery-policy.ts +237 -0
  138. package/src/core/aggregation/recovery-spend.ts +192 -0
  139. package/src/core/aggregation/runner/aggregation-runner.ts +27 -5
  140. package/src/core/aggregation/runner/events.ts +26 -7
  141. package/src/core/aggregation/runner/participant-runner.ts +75 -23
  142. package/src/core/aggregation/runner/service-runner.ts +120 -10
  143. package/src/core/aggregation/service.ts +260 -14
  144. package/src/core/aggregation/signing-session.ts +3 -3
  145. package/src/core/aggregation/transport/http/envelope.ts +3 -3
  146. package/src/core/aggregation/transport/http/inbox-buffer.ts +1 -1
  147. package/src/core/aggregation/transport/http/nonce-cache.ts +1 -1
  148. package/src/core/aggregation/transport/http/rate-limiter.ts +1 -1
  149. package/src/core/aggregation/transport/http/request-auth.ts +1 -1
  150. package/src/core/aggregation/transport/http/server.ts +1 -1
  151. package/src/core/aggregation/transport/http/sse-stream.ts +2 -2
  152. package/src/core/aggregation/transport/http/sse-writer.ts +1 -1
  153. package/src/core/aggregation/transport/in-memory.ts +1 -1
  154. package/src/core/aggregation/transport/nostr.ts +6 -6
  155. package/src/core/aggregation/transport/transport.ts +4 -4
  156. package/src/core/beacon/beacon.ts +16 -11
  157. package/src/core/beacon/cas-beacon.ts +7 -7
  158. package/src/core/beacon/interfaces.ts +1 -1
  159. package/src/core/beacon/singleton-beacon.ts +2 -2
  160. package/src/core/beacon/smt-beacon.ts +3 -3
  161. package/src/core/resolver.ts +8 -8
  162. package/src/core/updater.ts +6 -6
  163. package/src/did-btcr2.ts +2 -2
  164. package/src/index.ts +3 -0
@@ -8,10 +8,14 @@ const CAS_STRATEGY = {
8
8
  getDistributePayload(cohort) {
9
9
  return { casAnnouncement: cohort.casAnnouncement };
10
10
  },
11
- validateParticipantView({ participantDid, expectedHash, body }) {
11
+ validateParticipantView({ participantDid, included, expectedHash, body }) {
12
12
  const casAnnouncement = body.casAnnouncement;
13
13
  if (!casAnnouncement)
14
14
  return { matches: false };
15
+ if (!included) {
16
+ // Cooperative non-inclusion: the decliner must be ABSENT from the map.
17
+ return { matches: !(participantDid in casAnnouncement), casAnnouncement };
18
+ }
15
19
  return {
16
20
  matches: casAnnouncement[participantDid] === expectedHash,
17
21
  casAnnouncement,
@@ -27,10 +31,20 @@ const SMT_STRATEGY = {
27
31
  const proof = cohort.smtProofs?.get(participantDid);
28
32
  return { smtProof: proof };
29
33
  },
30
- validateParticipantView({ participantDid, submittedUpdate, body }) {
34
+ validateParticipantView({ participantDid, included, submittedUpdate, body }) {
31
35
  const smtProof = body.smtProof;
32
- if (!smtProof?.updateId || !smtProof?.nonce)
33
- return { matches: false };
36
+ const index = didToIndex(participantDid);
37
+ if (!included) {
38
+ // Cooperative non-inclusion: the proof has a nonce but no updateId by
39
+ // construction. The leaf is SHA-256(SHA-256(nonce)); do NOT run the
40
+ // inclusion-only updateId guard (a missing updateId is correct here).
41
+ if (!smtProof?.nonce || smtProof?.updateId)
42
+ return { matches: false, smtProof };
43
+ const candidateHash = blockHash(blockHash(base64UrlToHash(smtProof.nonce)));
44
+ return { matches: verifySerializedProof(smtProof, index, candidateHash), smtProof };
45
+ }
46
+ if (!smtProof?.updateId || !smtProof?.nonce || !submittedUpdate)
47
+ return { matches: false, smtProof };
34
48
  // Verify updateId matches the canonicalized update hash. Proof hash fields
35
49
  // are base64url (no padding) per the SMT Proof spec.
36
50
  const canonicalBytes = new TextEncoder().encode(canonicalize(submittedUpdate));
@@ -38,8 +52,7 @@ const SMT_STRATEGY = {
38
52
  if (smtProof.updateId !== expectedUpdateId) {
39
53
  return { matches: false, smtProof };
40
54
  }
41
- // Verify Merkle inclusion
42
- const index = didToIndex(participantDid);
55
+ // Verify Merkle inclusion. The leaf is SHA-256(SHA-256(nonce) || SHA-256(update)).
43
56
  const candidateHash = blockHash(blockHash(base64UrlToHash(smtProof.nonce)), base64UrlToHash(smtProof.updateId));
44
57
  return {
45
58
  matches: verifySerializedProof(smtProof, index, candidateHash),
@@ -1 +1 @@
1
- {"version":3,"file":"beacon-strategy.js","sourceRoot":"","sources":["../../../../src/core/aggregation/beacon-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAqDhH,MAAM,YAAY,GAA4B;IAC5C,IAAI,EAAG,WAAW;IAElB,mBAAmB,CAAC,MAAM;QACxB,MAAM,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IAED,oBAAoB,CAAC,MAAM;QACzB,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC;IACrD,CAAC;IAED,uBAAuB,CAAC,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE;QAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QAC7C,IAAG,CAAC,eAAe;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC/C,OAAO;YACL,OAAO,EAAG,eAAe,CAAC,cAAc,CAAC,KAAK,YAAY;YAC1D,eAAe;SAChB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,MAAM,YAAY,GAA4B;IAC5C,IAAI,EAAG,WAAW;IAElB,mBAAmB,CAAC,MAAM;QACxB,MAAM,CAAC,YAAY,EAAE,CAAC;IACxB,CAAC;IAED,oBAAoB,CAAC,MAAM,EAAE,cAAc;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;QACpD,OAAO,EAAE,QAAQ,EAAE,KAAuD,EAAE,CAAC;IAC/E,CAAC;IAED,uBAAuB,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE,IAAI,EAAE;QAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAqD,CAAC;QAC5E,IAAG,CAAC,QAAQ,EAAE,QAAQ,IAAI,CAAC,QAAQ,EAAE,KAAK;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACtE,2EAA2E;QAC3E,qDAAqD;QACrD,MAAM,cAAc,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,eAAqD,CAAC,CAAC,CAAC;QACrH,MAAM,gBAAgB,GAAG,eAAe,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;QACpE,IAAG,QAAQ,CAAC,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QACtC,CAAC;QACD,0BAA0B;QAC1B,MAAM,KAAK,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChH,OAAO;YACL,OAAO,EAAG,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAC;YAC/D,QAAQ;SACT,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,0DAA0D;AAC1D,MAAM,UAAU,GAAyC,IAAI,GAAG,CAAC;IAC/D,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC;IACjC,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC;CAClC,CAAC,CAAC;AAEH,2FAA2F;AAC3F,MAAM,UAAU,sBAAsB,CAAC,QAAiC;IACtE,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"beacon-strategy.js","sourceRoot":"","sources":["../../../../src/core/aggregation/beacon-strategy.ts"],"names":[],"mappings":"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"}
@@ -2,16 +2,17 @@ import { getNetwork } from '@did-btcr2/bitcoin';
2
2
  import { canonicalHash, canonicalize, hash } from '@did-btcr2/common';
3
3
  import { BTCR2MerkleTree } from '@did-btcr2/smt';
4
4
  import { schnorr } from '@noble/curves/secp256k1.js';
5
- import { hexToBytes, randomBytes } from '@noble/hashes/utils';
5
+ import { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils';
6
6
  import { p2tr } from '@scure/btc-signer';
7
7
  import { keyAggExport, keyAggregate, sortKeys } from '@scure/btc-signer/musig2';
8
8
  import { AggregationCohortError } from './errors.js';
9
+ import { DEFAULT_FUNDING_MODEL, buildRecoveryLeaves, resolveFallbackThreshold } from './recovery-policy.js';
9
10
  /**
10
- * Represents an Aggregation Cohort a set of Aggregation Participants who
11
+ * Represents an Aggregation Cohort: a set of Aggregation Participants who
11
12
  * submitted cryptographic material to an Aggregation Service to coordinate
12
13
  * signing of a shared n-of-n MuSig2 Bitcoin transaction.
13
14
  *
14
- * This is a pure data class it holds cohort state and provides computation
15
+ * This is a pure data class: it holds cohort state and provides computation
15
16
  * helpers (key aggregation, CAS Announcement building, SMT tree building).
16
17
  * It performs no I/O and emits no messages. Both AggregationService and
17
18
  * AggregationParticipant create their own AggregationCohort instances to
@@ -33,8 +34,8 @@ export class AggregationCohort {
33
34
  /** List of participant DIDs that have been accepted into the cohort. */
34
35
  participants = [];
35
36
  /**
36
- * Mapping from participant DID their compressed secp256k1 public key.
37
- * Distinct from {@link cohortKeys} (which is sorted per BIP-327) this lets
37
+ * Mapping from participant DID to their compressed secp256k1 public key.
38
+ * Distinct from {@link cohortKeys} (which is sorted per BIP-327): this lets
38
39
  * callers look up a participant's key without knowing their position in the
39
40
  * sorted array. Populated by the service at `acceptParticipant` time.
40
41
  */
@@ -42,16 +43,41 @@ export class AggregationCohort {
42
43
  /** Sorted list of cohort participants' compressed public keys. */
43
44
  #cohortKeys = [];
44
45
  /**
45
- * BIP-341 TapTweak `taggedHash("TapTweak", internalPubkey)` for a key-path-only
46
- * Taproot output. Despite prior naming, this is NOT a Merkle root: key-path-only
47
- * spends have no script tree.
46
+ * BIP-341 TapTweak scalar: `taggedHash("TapTweak", internalPubkey || tapMerkleRoot)`.
47
+ * The beacon output is an internal key (the MuSig2 aggregate) plus a script
48
+ * tree (the recovery leaves), so the tweak commits to the tree's Merkle root.
49
+ * The MuSig2 signing session applies this as an x-only tweak; a value that does
50
+ * not match the root the funded address was derived from silently yields an
51
+ * invalid key-path signature.
48
52
  */
49
53
  tapTweak = new Uint8Array();
50
- /** The n-of-n MuSig2 Taproot beacon address. */
54
+ /** The n-of-n MuSig2 aggregate internal key, x-only (32 bytes), set by computeBeaconAddress(). */
55
+ internalKey = new Uint8Array();
56
+ /** BIP-341 Taproot Merkle root of the recovery script tree, set by computeBeaconAddress(). */
57
+ tapMerkleRoot = new Uint8Array();
58
+ /** Operator recovery key, x-only (32 bytes). Used to build the CSV recovery leaf. */
59
+ recoveryKey;
60
+ /** Relative-timelock (BIP-68 nSequence) before the recovery leaf is spendable. */
61
+ recoverySequence;
62
+ /** Funding model governing the recovery leaves (default 'operator-funded'). */
63
+ fundingModel;
64
+ /**
65
+ * Advertised k of the k-of-n fallback leaf, or undefined to default to n-1 at
66
+ * address computation. Read the resolved value via {@link effectiveFallbackThreshold}.
67
+ */
68
+ fallbackThreshold;
69
+ /** The Taproot beacon address: key path is the MuSig2 aggregate, script path is fallback + recovery. */
51
70
  beaconAddress = '';
52
71
  /** Pending DID updates submitted by participants, keyed by DID. */
53
72
  pendingUpdates = new Map();
54
- /** CAS Beacon Announcement Map (DID → updateHash), set by buildCASAnnouncement(). */
73
+ /**
74
+ * Participant DIDs that explicitly declined to submit an update this round
75
+ * (cooperative non-inclusion). A decliner is absent from the CAS Announcement
76
+ * Map and carries a non-inclusion leaf in the SMT, yet still signs. Kept
77
+ * disjoint from {@link pendingUpdates} so CAS correctness holds by construction.
78
+ */
79
+ nonIncluded = new Set();
80
+ /** CAS Beacon Announcement Map (DID to updateHash), set by buildCASAnnouncement(). */
55
81
  casAnnouncement;
56
82
  /** Per-participant SMT proofs, set by buildSMTTree(). */
57
83
  smtProofs;
@@ -61,7 +87,7 @@ export class AggregationCohort {
61
87
  validationAcks = new Set();
62
88
  /** Set of participant DIDs that have rejected the aggregated data. */
63
89
  validationRejections = new Set();
64
- constructor({ id, minParticipants, serviceDid, network, beaconType }) {
90
+ constructor({ id, minParticipants, serviceDid, network, beaconType, recoveryKey, recoverySequence, fundingModel, fallbackThreshold }) {
65
91
  this.id = id || crypto.randomUUID();
66
92
  // `?? 2` (not `|| 2`) so a deliberately-passed 0 is preserved rather than
67
93
  // silently coerced; the service rejects an invalid count at createCohort.
@@ -69,6 +95,10 @@ export class AggregationCohort {
69
95
  this.serviceDid = serviceDid || '';
70
96
  this.network = network;
71
97
  this.beaconType = beaconType || 'CASBeacon';
98
+ this.recoveryKey = recoveryKey;
99
+ this.recoverySequence = recoverySequence;
100
+ this.fundingModel = fundingModel ?? DEFAULT_FUNDING_MODEL;
101
+ this.fallbackThreshold = fallbackThreshold;
72
102
  }
73
103
  /** Sorted cohort keys (sorted on assignment per BIP-327). */
74
104
  get cohortKeys() {
@@ -78,22 +108,60 @@ export class AggregationCohort {
78
108
  this.#cohortKeys = sortKeys(keys);
79
109
  }
80
110
  /**
81
- * Computes the n-of-n MuSig2 Taproot beacon address from cohort keys.
82
- * Sets `tapTweak` to the BIP-341 key-path-only tweak.
111
+ * The resolved k of the k-of-n fallback leaf: the advertised
112
+ * {@link fallbackThreshold}, or n-1 (floored at 1) when unadvertised, where n is
113
+ * the current cohort size. This is the value the beacon address commits to and
114
+ * the spend builders must reproduce. Returns 0 before any cohort keys are set.
115
+ */
116
+ get effectiveFallbackThreshold() {
117
+ if (this.#cohortKeys.length === 0)
118
+ return 0;
119
+ return resolveFallbackThreshold(this.fallbackThreshold, this.#cohortKeys.length);
120
+ }
121
+ /**
122
+ * Computes the Taproot beacon address from the cohort keys and recovery params.
123
+ *
124
+ * The output's key path is the n-of-n MuSig2 aggregate of the cohort keys; its
125
+ * script path is the recovery tree (a CSV recovery leaf so a missing signer
126
+ * cannot permanently lock the UTXO). Sets `internalKey`, `tapMerkleRoot`, and
127
+ * the `tapTweak` the MuSig2 session must apply for the key-path spend.
128
+ *
129
+ * The tweak is derived from the Merkle root the address was built with (read
130
+ * back from the payment), never recomputed by hand, so the MuSig2 key-path
131
+ * signature is guaranteed to validate against the funded address.
83
132
  */
84
133
  computeBeaconAddress() {
85
134
  if (this.#cohortKeys.length === 0) {
86
135
  throw new AggregationCohortError('Cannot compute beacon address: no cohort keys.', 'NO_COHORT_KEYS', { cohortId: this.id });
87
136
  }
137
+ if (!this.recoveryKey || this.recoveryKey.length === 0 || this.recoverySequence === undefined) {
138
+ throw new AggregationCohortError('Cannot compute beacon address: missing recovery key or sequence.', 'NO_RECOVERY_PARAMS', { cohortId: this.id });
139
+ }
88
140
  const keyAggContext = keyAggregate(this.#cohortKeys);
89
141
  const aggPubkey = keyAggExport(keyAggContext);
90
- // Derive the address for the cohort's network. Without the network arg
91
- // p2tr defaults to mainnet, so a mutinynet/signet/regtest cohort would
92
- // otherwise advertise a `bc1p...` address that no participant can fund.
93
- const payment = p2tr(aggPubkey, undefined, getNetwork(this.network));
94
- // BIP-341: key-path-only P2TR has no script tree. Compute the tweak:
95
- // taggedHash("TapTweak", internalPubkey).
96
- this.tapTweak = schnorr.utils.taggedHash('TapTweak', aggPubkey);
142
+ // The beacon output commits to the script tree (k-of-n fallback leaf + CSV
143
+ // recovery leaf) alongside the MuSig2 internal key. Derive the address for
144
+ // the cohort's network. Without the network arg p2tr defaults to mainnet, so
145
+ // a mutinynet/signet/regtest cohort would otherwise advertise a `bc1p...`
146
+ // address that no participant can fund.
147
+ const leaves = buildRecoveryLeaves(this.fundingModel, {
148
+ recoveryKey: this.recoveryKey,
149
+ recoverySequence: this.recoverySequence,
150
+ cohortKeys: this.#cohortKeys,
151
+ fallbackThreshold: resolveFallbackThreshold(this.fallbackThreshold, this.#cohortKeys.length),
152
+ });
153
+ // allowUnknownOutputs: the CSV recovery leaf is a custom script, not one of
154
+ // p2tr's recognized templates (tr_ns/tr_ms), so the template check must be
155
+ // waived. The leaf hash (and thus the address) is computed from the raw
156
+ // script bytes regardless.
157
+ const payment = p2tr(aggPubkey, leaves, getNetwork(this.network), true);
158
+ // BIP-341: the key-path tweak commits to the script tree's Merkle root.
159
+ // taggedHash("TapTweak", internalPubkey || tapMerkleRoot). Use the root the
160
+ // library committed to (payment.tapMerkleRoot) so the tweak matches the
161
+ // funded address byte-for-byte.
162
+ this.internalKey = aggPubkey;
163
+ this.tapMerkleRoot = payment.tapMerkleRoot;
164
+ this.tapTweak = schnorr.utils.taggedHash('TapTweak', concatBytes(aggPubkey, payment.tapMerkleRoot));
97
165
  if (!payment.address) {
98
166
  throw new AggregationCohortError('Failed to compute Taproot address', 'BEACON_ADDRESS_ERROR', { cohortId: this.id });
99
167
  }
@@ -132,17 +200,45 @@ export class AggregationCohort {
132
200
  }
133
201
  this.pendingUpdates.set(participantDid, signedUpdate);
134
202
  }
203
+ /**
204
+ * Record that a participant declined to submit an update this round
205
+ * (cooperative non-inclusion). The member stays in the cohort and still signs.
206
+ */
207
+ addNonInclusion(participantDid) {
208
+ if (!this.participants.includes(participantDid)) {
209
+ throw new AggregationCohortError(`Participant ${participantDid} is not in cohort ${this.id}.`, 'UNKNOWN_PARTICIPANT', { cohortId: this.id, participantDid });
210
+ }
211
+ // A DID cannot both submit and decline. The service guards re-submission, but
212
+ // keep the invariant local so the response gate and builders stay consistent.
213
+ if (this.pendingUpdates.has(participantDid)) {
214
+ throw new AggregationCohortError(`Participant ${participantDid} already submitted an update; cannot also decline.`, 'CONFLICTING_RESPONSE', { cohortId: this.id, participantDid });
215
+ }
216
+ this.nonIncluded.add(participantDid);
217
+ }
135
218
  hasAllUpdates() {
136
219
  return this.pendingUpdates.size === this.participants.length;
137
220
  }
221
+ /**
222
+ * True when every participant has responded for this round, either with an
223
+ * update or with an explicit non-inclusion. This is the aggregation gate when
224
+ * non-inclusion is in play; it generalizes {@link hasAllUpdates} the same way
225
+ * {@link hasAllValidationResponses} generalizes a unanimous ack.
226
+ */
227
+ hasAllResponses() {
228
+ return this.pendingUpdates.size + this.nonIncluded.size === this.participants.length;
229
+ }
138
230
  /**
139
231
  * Builds a CAS Announcement Map from collected updates.
140
- * Maps each participant DID base64url canonical hash of their signed update.
232
+ * Maps each participant DID to base64url canonical hash of their signed update.
141
233
  * Computes signal bytes as SHA-256 of canonicalized announcement.
234
+ *
235
+ * Members who declined (cooperative non-inclusion) are naturally absent from
236
+ * the map: the body iterates {@link pendingUpdates}, which never holds a
237
+ * decliner. Absence from the map is exactly the CAS non-inclusion signal.
142
238
  */
143
239
  buildCASAnnouncement() {
144
- if (!this.hasAllUpdates()) {
145
- throw new AggregationCohortError('Cannot build CAS Announcement: not all updates collected.', 'INCOMPLETE_UPDATES', { cohortId: this.id, collected: this.pendingUpdates.size, total: this.participants.length });
240
+ if (!this.hasAllResponses()) {
241
+ throw new AggregationCohortError('Cannot build CAS Announcement: not all participants have responded.', 'INCOMPLETE_RESPONSES', { cohortId: this.id, updates: this.pendingUpdates.size, declined: this.nonIncluded.size, total: this.participants.length });
146
242
  }
147
243
  const announcement = {};
148
244
  for (const [did, signedUpdate] of this.pendingUpdates) {
@@ -153,27 +249,40 @@ export class AggregationCohort {
153
249
  return announcement;
154
250
  }
155
251
  /**
156
- * Builds an SMT tree from collected updates.
157
- * Each entry uses a random 32-byte nonce + canonicalized signed update bytes.
158
- * Stores per-participant proofs and the SMT root as signalBytes.
252
+ * Builds an SMT tree with one leaf per participant.
253
+ *
254
+ * A member who submitted an update gets an inclusion leaf
255
+ * (SHA-256(SHA-256(nonce) || SHA-256(update))); a member who declined gets a
256
+ * non-inclusion leaf (SHA-256(SHA-256(nonce)), the `signedUpdate` entry field
257
+ * omitted). The cohort mints each member's nonce and returns it inside that
258
+ * member's serialized proof, so a decliner can self-validate its own
259
+ * non-inclusion slot and the resolver can recompute the leaf. Stores
260
+ * per-participant proofs and the SMT root as signalBytes.
159
261
  */
160
262
  buildSMTTree() {
161
- if (!this.hasAllUpdates()) {
162
- throw new AggregationCohortError('Cannot build SMT tree: not all updates collected.', 'INCOMPLETE_UPDATES', { cohortId: this.id });
263
+ if (!this.hasAllResponses()) {
264
+ throw new AggregationCohortError('Cannot build SMT tree: not all participants have responded.', 'INCOMPLETE_RESPONSES', { cohortId: this.id, updates: this.pendingUpdates.size, declined: this.nonIncluded.size, total: this.participants.length });
163
265
  }
164
266
  const tree = new BTCR2MerkleTree();
165
267
  const entries = [];
166
268
  const encoder = new TextEncoder();
167
- for (const [did, signedUpdate] of this.pendingUpdates) {
168
- const canonicalBytes = encoder.encode(canonicalize(signedUpdate));
269
+ // Slot every participant: an inclusion leaf for submitters, a non-inclusion
270
+ // leaf (signedUpdate omitted) for decliners.
271
+ for (const did of this.participants) {
169
272
  const nonce = randomBytes(32);
170
- entries.push({ did, nonce, signedUpdate: canonicalBytes });
273
+ const signedUpdate = this.pendingUpdates.get(did);
274
+ if (signedUpdate) {
275
+ entries.push({ did, nonce, signedUpdate: encoder.encode(canonicalize(signedUpdate)) });
276
+ }
277
+ else {
278
+ entries.push({ did, nonce });
279
+ }
171
280
  }
172
281
  tree.addEntries(entries);
173
282
  tree.finalize();
174
283
  this.signalBytes = tree.rootHash;
175
284
  this.smtProofs = new Map();
176
- for (const [did] of this.pendingUpdates) {
285
+ for (const did of this.participants) {
177
286
  this.smtProofs.set(did, tree.proof(did));
178
287
  }
179
288
  return this.smtProofs;
@@ -196,7 +305,7 @@ export class AggregationCohort {
196
305
  return this.validationAcks.size + this.validationRejections.size === this.participants.length;
197
306
  }
198
307
  /**
199
- * True when all participants approved. Note: differs from {@link hasAllValidationResponses}
308
+ * True when all participants approved. Note: differs from {@link hasAllValidationResponses},
200
309
  * this returns false if any participant rejected, even if all responses are in.
201
310
  */
202
311
  isFullyValidated() {
@@ -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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGtE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEhF,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAkB5G;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,iBAAiB;IAC5B,wCAAwC;IACxC,EAAE,CAAS;IAEX,2DAA2D;IAC3D,UAAU,CAAS;IAEnB,sEAAsE;IACtE,eAAe,CAAS;IAExB,uEAAuE;IACvE,OAAO,CAAS;IAEhB,qEAAqE;IACrE,UAAU,CAAS;IAEnB,wEAAwE;IACxE,YAAY,GAAkB,EAAE,CAAC;IAEjC;;;;;OAKG;IACH,eAAe,GAA4B,IAAI,GAAG,EAAE,CAAC;IAErD,kEAAkE;IAClE,WAAW,GAAsB,EAAE,CAAC;IAEpC;;;;;;;OAOG;IACH,QAAQ,GAAe,IAAI,UAAU,EAAE,CAAC;IAExC,kGAAkG;IAClG,WAAW,GAAe,IAAI,UAAU,EAAE,CAAC;IAE3C,8FAA8F;IAC9F,aAAa,GAAe,IAAI,UAAU,EAAE,CAAC;IAE7C,qFAAqF;IACrF,WAAW,CAAc;IAEzB,kFAAkF;IAClF,gBAAgB,CAAU;IAE1B,+EAA+E;IAC/E,YAAY,CAAe;IAE3B;;;OAGG;IACH,iBAAiB,CAAU;IAE3B,wGAAwG;IACxG,aAAa,GAAW,EAAE,CAAC;IAE3B,mEAAmE;IACnE,cAAc,GAAmC,IAAI,GAAG,EAAE,CAAC;IAE3D;;;;;OAKG;IACH,WAAW,GAAgB,IAAI,GAAG,EAAE,CAAC;IAErC,sFAAsF;IACtF,eAAe,CAAmB;IAElC,yDAAyD;IACzD,SAAS,CAAmC;IAE5C,sFAAsF;IACtF,WAAW,CAAc;IAEzB,sEAAsE;IACtE,cAAc,GAAgB,IAAI,GAAG,EAAE,CAAC;IAExC,sEAAsE;IACtE,oBAAoB,GAAgB,IAAI,GAAG,EAAE,CAAC;IAE9C,YAAY,EAAE,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAA2B;QAC3J,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACpC,0EAA0E;QAC1E,0EAA0E;QAC1E,IAAI,CAAC,eAAe,GAAG,eAAe,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,WAAW,CAAC;QAC5C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,qBAAqB,CAAC;QAC1D,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;IAED,6DAA6D;IAC7D,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,IAAI,UAAU,CAAC,IAAuB;QACpC,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,IAAW,0BAA0B;QACnC,IAAG,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,wBAAwB,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;;;OAWG;IACI,oBAAoB;QACzB,IAAG,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,sBAAsB,CAC9B,gDAAgD,EAChD,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CACxC,CAAC;QACJ,CAAC;QACD,IAAG,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YAC7F,MAAM,IAAI,sBAAsB,CAC9B,kEAAkE,EAClE,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAC5C,CAAC;QACJ,CAAC;QACD,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QAE9C,2EAA2E;QAC3E,2EAA2E;QAC3E,6EAA6E;QAC7E,0EAA0E;QAC1E,wCAAwC;QACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE;YACpD,WAAW,EAAS,IAAI,CAAC,WAAW;YACpC,gBAAgB,EAAI,IAAI,CAAC,gBAAgB;YACzC,UAAU,EAAU,IAAI,CAAC,WAAW;YACpC,iBAAiB,EAAG,wBAAwB,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;SAC9F,CAAC,CAAC;QACH,4EAA4E;QAC5E,2EAA2E;QAC3E,wEAAwE;QACxE,2BAA2B;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QAExE,wEAAwE;QACxE,4EAA4E;QAC5E,wEAAwE;QACxE,gCAAgC;QAChC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAEpG,IAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,sBAAsB,CAC9B,mCAAmC,EACnC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAC9C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;QACrC,OAAO,OAAO,CAAC,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACI,kBAAkB,CACvB,gBAAwB,EACxB,aAA4B,EAC5B,qBAA6B;QAE7B,IAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,sBAAsB,CAC9B,uCAAuC,IAAI,CAAC,EAAE,GAAG,EACjD,yBAAyB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,gBAAgB,EAAE,CACnE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7C,IAAG,QAAQ,KAAK,qBAAqB,EAAE,CAAC;YACtC,MAAM,IAAI,sBAAsB,CAC9B,2BAA2B,QAAQ,4BAA4B,qBAAqB,GAAG,EACvF,yBAAyB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,CAC5F,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACI,kBAAkB,CAAC,GAAW;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzC,IAAG,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CACpC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CACzD,CAAC;IACJ,CAAC;IAEM,SAAS,CAAC,cAAsB,EAAE,YAA+B;QACtE,IAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,sBAAsB,CAC9B,eAAe,cAAc,qBAAqB,IAAI,CAAC,EAAE,GAAG,EAC5D,qBAAqB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,CAC7D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;IAED;;;OAGG;IACI,eAAe,CAAC,cAAsB;QAC3C,IAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,sBAAsB,CAC9B,eAAe,cAAc,qBAAqB,IAAI,CAAC,EAAE,GAAG,EAC5D,qBAAqB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,CAC7D,CAAC;QACJ,CAAC;QACD,8EAA8E;QAC9E,8EAA8E;QAC9E,IAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,sBAAsB,CAC9B,eAAe,cAAc,oDAAoD,EACjF,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,CAC9D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAEM,aAAa;QAClB,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAC/D,CAAC;IAED;;;;;OAKG;IACI,eAAe;QACpB,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IACvF,CAAC;IAED;;;;;;;;OAQG;IACI,oBAAoB;QACzB,IAAG,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,MAAM,IAAI,sBAAsB,CAC9B,qEAAqE,EACrE,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CACnJ,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAoB,EAAE,CAAC;QACzC,KAAI,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACrD,YAAY,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,eAAe,GAAG,YAAY,CAAC;QACpC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC;QACpD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED;;;;;;;;;;OAUG;IACI,YAAY;QACjB,IAAG,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3B,MAAM,IAAI,sBAAsB,CAC9B,6DAA6D,EAC7D,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CACnJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;QACnC,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAElC,4EAA4E;QAC5E,6CAA6C;QAC7C,KAAI,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClD,IAAG,YAAY,EAAE,CAAC;gBAChB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;YACzF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAC3B,KAAI,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAEM,aAAa,CAAC,cAAsB,EAAE,QAAiB;QAC5D,IAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,sBAAsB,CAC9B,uBAAuB,cAAc,cAAc,IAAI,CAAC,EAAE,GAAG,EAC7D,qBAAqB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,CAC7D,CAAC;QACJ,CAAC;QACD,IAAG,QAAQ,EAAE,CAAC;YACZ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED;;OAEG;IACI,yBAAyB;QAC9B,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAChG,CAAC;IAED;;;OAGG;IACI,gBAAgB;QACrB,OAAO,IAAI,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC;eACtC,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAC7D,CAAC;CACF"}
@@ -14,8 +14,11 @@
14
14
  * conditions are advertised metadata only - the protocol performs no payment or
15
15
  * settlement (consistent with ADR 008).
16
16
  */
17
+ import { MAX_RECOVERY_SEQUENCE } from './recovery-policy.js';
17
18
  /** Beacon types that support aggregation (singleton is single-party only, per ADR 037). */
18
19
  export const KNOWN_BEACON_TYPES = ['CASBeacon', 'SMTBeacon'];
20
+ /** Funding models an operator may advertise. Only 'operator-funded' is implemented (ADR 042). */
21
+ export const KNOWN_FUNDING_MODELS = ['operator-funded', 'participant-funded'];
19
22
  /** Validate an optional [min, max] integer pair. */
20
23
  function checkPair(problems, label, min, max) {
21
24
  if (min !== undefined && (!Number.isInteger(min) || min < 0)) {
@@ -68,8 +71,32 @@ export function validateCohortConditions(c) {
68
71
  if (c.pendingUpdateTrigger !== undefined && (!Number.isInteger(c.pendingUpdateTrigger) || c.pendingUpdateTrigger < 1)) {
69
72
  problems.push('pendingUpdateTrigger must be an integer >= 1');
70
73
  }
74
+ // Fallback threshold (k of the k-of-n fallback leaf). Optional; when advertised
75
+ // it must be a positive integer and cannot exceed maxParticipants (the binding
76
+ // upper bound against the actual cohort size n is checked at keygen, where n is
77
+ // known). See ADR 042.
78
+ if (c.fallbackThreshold !== undefined) {
79
+ if (!Number.isInteger(c.fallbackThreshold) || c.fallbackThreshold < 1) {
80
+ problems.push('fallbackThreshold must be an integer >= 1');
81
+ }
82
+ else if (c.maxParticipants !== undefined && Number.isInteger(c.maxParticipants) && c.fallbackThreshold > c.maxParticipants) {
83
+ problems.push('fallbackThreshold must be <= maxParticipants');
84
+ }
85
+ }
71
86
  checkCost(problems, 'costOfEnrollment', c.costOfEnrollment);
72
87
  checkCost(problems, 'costPerAnnouncement', c.costPerAnnouncement);
88
+ // Recovery params: the beacon output's CSV recovery leaf. Required so a
89
+ // missing signer can never permanently lock the funded UTXO (ADR 042). The
90
+ // key is an x-only (32-byte) Schnorr public key, carried as 64 hex chars.
91
+ if (typeof c.recoveryKey !== 'string' || !/^[0-9a-fA-F]{64}$/.test(c.recoveryKey)) {
92
+ problems.push('recoveryKey must be a 64-character hex string (x-only public key)');
93
+ }
94
+ if (!Number.isInteger(c.recoverySequence) || c.recoverySequence < 1 || c.recoverySequence > MAX_RECOVERY_SEQUENCE) {
95
+ problems.push(`recoverySequence must be a block-based BIP-68 relative timelock in [1, ${MAX_RECOVERY_SEQUENCE}]`);
96
+ }
97
+ if (c.fundingModel !== undefined && !KNOWN_FUNDING_MODELS.includes(c.fundingModel)) {
98
+ problems.push(`fundingModel must be one of ${KNOWN_FUNDING_MODELS.join(', ')}`);
99
+ }
73
100
  return problems;
74
101
  }
75
102
  //# sourceMappingURL=conditions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conditions.js","sourceRoot":"","sources":["../../../../src/core/aggregation/conditions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conditions.js","sourceRoot":"","sources":["../../../../src/core/aggregation/conditions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Fallback spend builder for aggregate beacon outputs.
3
+ *
4
+ * An aggregate beacon UTXO is a Taproot output whose key path is the cohort's
5
+ * n-of-n MuSig2 aggregate key and whose script path carries a k-of-n fallback
6
+ * leaf (`p2tr_ms` CHECKSIGADD) plus a CSV recovery leaf (see
7
+ * {@link ./recovery-policy.ts} and ADR 042). When the optimistic n-of-n key path
8
+ * stalls (a missing or defecting signer), the cohort can still push the SAME
9
+ * announcement transaction through the fallback leaf with any k members'
10
+ * signatures, instead of abandoning the round or waiting out the recovery
11
+ * timelock.
12
+ *
13
+ * Unlike the MuSig2 key path, the fallback is a plain k-of-n script-path spend:
14
+ * each signer produces a standalone BIP-340 signature over the script-path
15
+ * sighash (no nonce round), and the coordinator assembles k of them into the
16
+ * witness. The coordinator never holds a participant secret - it injects the
17
+ * collected signatures and finalizes.
18
+ *
19
+ * This module is pure with respect to the network: it takes the beacon
20
+ * transaction, the cohort and recovery parameters, the spent output, and the
21
+ * collected signatures, and returns a finalized {@link Transaction}.
22
+ * Broadcasting is the caller's concern.
23
+ */
24
+ import { getNetwork } from '@did-btcr2/bitcoin';
25
+ import { schnorr } from '@noble/curves/secp256k1.js';
26
+ import { SigHash, p2tr } from '@scure/btc-signer';
27
+ import { keyAggExport, keyAggregate, sortKeys } from '@scure/btc-signer/musig2';
28
+ import { AggregationCohortError } from './errors.js';
29
+ import { DEFAULT_FUNDING_MODEL, TAPROOT_LEAF_VERSION, buildFallbackLeaf, buildRecoveryLeaves, resolveFallbackThreshold, tapLeafHash, } from './recovery-policy.js';
30
+ function bytesEqual(a, b) {
31
+ return a.length === b.length && a.every((x, i) => x === b[i]);
32
+ }
33
+ /**
34
+ * Compute the BIP-341 script-path sighash a cohort member must sign to authorize
35
+ * the fallback spend. The leaf is the k-of-n fallback leaf; signers produce a
36
+ * standalone BIP-340 signature over this digest with SIGHASH_DEFAULT.
37
+ */
38
+ export function fallbackSighash(tx, inputIndex, prevOutScript, prevOutValue, fallbackLeafScript) {
39
+ return tx.preimageWitnessV1(inputIndex, [prevOutScript], SigHash.DEFAULT, [prevOutValue], undefined, fallbackLeafScript, TAPROOT_LEAF_VERSION);
40
+ }
41
+ /**
42
+ * Assemble and finalize a k-of-n fallback spend of an aggregate beacon UTXO.
43
+ *
44
+ * Reconstructs the funded Taproot output (MuSig2 internal key + fallback/recovery
45
+ * script tree), verifies each collected signature against the script-path
46
+ * sighash and a cohort key, injects exactly k distinct valid signatures into the
47
+ * fallback leaf, and finalizes the witness. The returned transaction is the same
48
+ * announcement the optimistic path would have produced, signed via the script
49
+ * path instead of the key path.
50
+ *
51
+ * @throws {AggregationCohortError} when there are no cohort keys, the spent
52
+ * script does not match the reconstructed tree output, or fewer than k valid
53
+ * distinct signatures were supplied.
54
+ */
55
+ export function buildFallbackSpend(params) {
56
+ const { pendingTx, cohortKeys, recoveryKey, recoverySequence, fundingModel, network, prevOutScript, prevOutValue, signatures, } = params;
57
+ const inputIndex = params.inputIndex ?? 0;
58
+ if (cohortKeys.length === 0) {
59
+ throw new AggregationCohortError('Cannot build fallback spend: no cohort keys.', 'NO_COHORT_KEYS');
60
+ }
61
+ // Resolve k the same way the cohort did, so the reconstructed leaf matches.
62
+ const fallbackThreshold = resolveFallbackThreshold(params.fallbackThreshold, cohortKeys.length);
63
+ // Reconstruct the funded output the same way the cohort derived its address.
64
+ const internalKey = keyAggExport(keyAggregate(sortKeys(cohortKeys)));
65
+ const leaves = buildRecoveryLeaves(fundingModel ?? DEFAULT_FUNDING_MODEL, {
66
+ recoveryKey, recoverySequence, cohortKeys, fallbackThreshold,
67
+ });
68
+ const net = getNetwork(network);
69
+ // allowUnknownOutputs: the CSV recovery leaf is a custom script (see cohort.ts).
70
+ const payment = p2tr(internalKey, leaves, net, true);
71
+ // The output we are spending must be the cohort's funded beacon output; if the
72
+ // reconstructed tree script differs, the witness would not match the chain.
73
+ if (!bytesEqual(payment.script, prevOutScript)) {
74
+ throw new AggregationCohortError('Reconstructed beacon output script does not match the spent prevout script.', 'PREVOUT_SCRIPT_MISMATCH');
75
+ }
76
+ const fallbackLeaf = buildFallbackLeaf({ cohortKeys, fallbackThreshold });
77
+ // Locate the fallback leaf's tapLeafScript entry: each entry is
78
+ // [controlBlock, script || leafVersion]; strip the trailing version byte to
79
+ // compare the script.
80
+ const leafEntry = payment.tapLeafScript?.find(([, scriptVer]) => {
81
+ const script = scriptVer.slice(0, scriptVer.length - 1);
82
+ return bytesEqual(script, fallbackLeaf);
83
+ });
84
+ if (!leafEntry) {
85
+ throw new AggregationCohortError('Could not locate the fallback leaf in the reconstructed beacon output.', 'FALLBACK_LEAF_NOT_FOUND');
86
+ }
87
+ // Validate the collected signatures against the script-path sighash. The leaf
88
+ // is keyed by x-only cohort keys, so a valid signature must verify against one
89
+ // of them. Keep only distinct, valid signatures (first occurrence per key).
90
+ const cohortXOnly = sortKeys(cohortKeys).map(k => k.slice(1));
91
+ const tx = pendingTx;
92
+ const sighash = fallbackSighash(tx, inputIndex, prevOutScript, prevOutValue, fallbackLeaf);
93
+ const leafHash = tapLeafHash(fallbackLeaf);
94
+ const accepted = new Map(); // x-only hex to signature
95
+ for (const { pubKey, signature } of signatures) {
96
+ if (pubKey.length !== 32 || signature.length !== 64)
97
+ continue;
98
+ const isCohortKey = cohortXOnly.some(k => bytesEqual(k, pubKey));
99
+ if (!isCohortKey)
100
+ continue;
101
+ const hex = Array.from(pubKey, b => b.toString(16).padStart(2, '0')).join('');
102
+ if (accepted.has(hex))
103
+ continue;
104
+ let ok = false;
105
+ try {
106
+ ok = schnorr.verify(signature, sighash, pubKey);
107
+ }
108
+ catch {
109
+ ok = false;
110
+ }
111
+ if (ok)
112
+ accepted.set(hex, signature);
113
+ }
114
+ if (accepted.size < fallbackThreshold) {
115
+ throw new AggregationCohortError(`Not enough valid fallback signatures: have ${accepted.size}, need ${fallbackThreshold}.`, 'NOT_ENOUGH_FALLBACK_SIGNATURES', { have: accepted.size, need: fallbackThreshold });
116
+ }
117
+ // A k-of-n CHECKSIGADD leaf demands EXACTLY k satisfied signatures (the final
118
+ // <k> NUMEQUAL fails if the running count differs), so inject exactly k.
119
+ const chosen = cohortXOnly
120
+ .filter(k => accepted.has(Array.from(k, b => b.toString(16).padStart(2, '0')).join('')))
121
+ .slice(0, fallbackThreshold);
122
+ tx.updateInput(inputIndex, {
123
+ tapLeafScript: [leafEntry],
124
+ tapScriptSig: chosen.map(pubKey => {
125
+ const hex = Array.from(pubKey, b => b.toString(16).padStart(2, '0')).join('');
126
+ return [{ pubKey, leafHash }, accepted.get(hex)];
127
+ }),
128
+ });
129
+ tx.finalize();
130
+ return tx;
131
+ }
132
+ //# sourceMappingURL=fallback-spend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback-spend.js","sourceRoot":"","sources":["../../../../src/core/aggregation/fallback-spend.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/core/aggregation/messages/base.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAoC1C,MAAM,OAAO,WAAW;IACf,IAAI,CAAS;IACb,OAAO,CAAS;IAChB,EAAE,CAAU;IACZ,IAAI,CAAS;IACb,IAAI,CAAY;IAEvB,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAQ;QACjD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,wBAAwB,CAAC;QACnD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACI,MAAM;QACX,OAAO;YACL,IAAI,EAAM,IAAI,CAAC,IAAI;YACnB,OAAO,EAAG,IAAI,CAAC,OAAO;YACtB,EAAE,EAAQ,IAAI,CAAC,EAAE;YACjB,IAAI,EAAM,IAAI,CAAC,IAAI;YACnB,IAAI,EAAM,IAAI,CAAC,IAAI;SACpB,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/core/aggregation/messages/base.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AA0C1C,MAAM,OAAO,WAAW;IACf,IAAI,CAAS;IACb,OAAO,CAAS;IAChB,EAAE,CAAU;IACZ,IAAI,CAAS;IACb,IAAI,CAAY;IAEvB,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAQ;QACjD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,wBAAwB,CAAC;QACnD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACI,MAAM;QACX,OAAO;YACL,IAAI,EAAM,IAAI,CAAC,IAAI;YACnB,OAAO,EAAG,IAAI,CAAC,OAAO;YACtB,EAAE,EAAQ,IAAI,CAAC,EAAE;YACjB,IAAI,EAAM,IAAI,CAAC,IAAI;YACnB,IAAI,EAAM,IAAI,CAAC,IAAI;SACpB,CAAC;IACJ,CAAC;CACF"}