@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
@@ -13,6 +13,8 @@
13
13
 
14
14
  import type { SerializedSMTProof } from '@did-btcr2/smt';
15
15
  import type { CohortConditions } from '../conditions.js';
16
+ import { KNOWN_FUNDING_MODELS } from '../conditions.js';
17
+ import { MAX_RECOVERY_SEQUENCE } from '../recovery-policy.js';
16
18
  import type { BaseMessage } from './base.js';
17
19
  import {
18
20
  AGGREGATED_NONCE,
@@ -22,8 +24,11 @@ import {
22
24
  COHORT_OPT_IN_ACCEPT,
23
25
  COHORT_READY,
24
26
  DISTRIBUTE_AGGREGATED_DATA,
27
+ FALLBACK_AUTHORIZATION_REQUEST,
28
+ FALLBACK_SIGNATURE,
25
29
  NONCE_CONTRIBUTION,
26
30
  SIGNATURE_AUTHORIZATION,
31
+ SUBMIT_NONINCLUDED,
27
32
  SUBMIT_UPDATE,
28
33
  VALIDATION_ACK,
29
34
  } from './constants.js';
@@ -59,6 +64,15 @@ export interface SubmitUpdateBody {
59
64
  signedUpdate: Record<string, unknown>;
60
65
  }
61
66
 
67
+ /**
68
+ * A member declines to submit an update this round (cooperative non-inclusion).
69
+ * Carries only the cohortId; membership is proven by the signed transport
70
+ * envelope (the sender DID), so no payload is needed.
71
+ */
72
+ export interface SubmitNonIncludedBody {
73
+ cohortId: string;
74
+ }
75
+
62
76
  export interface DistributeAggregatedDataBody {
63
77
  cohortId: string;
64
78
  beaconType: string;
@@ -100,6 +114,33 @@ export interface SignatureAuthorizationBody {
100
114
  partialSignature: Uint8Array;
101
115
  }
102
116
 
117
+ /**
118
+ * Service asks members to authorize the k-of-n fallback (script-path) spend of
119
+ * the SAME beacon transaction (ADR 042). Carries the unsigned tx and the spent
120
+ * output so each member recomputes the script-path sighash itself. The fallback
121
+ * leaf script is included for cross-check; members recompute it from their own
122
+ * cohort state.
123
+ */
124
+ export interface FallbackAuthorizationRequestBody {
125
+ cohortId: string;
126
+ sessionId: string;
127
+ pendingTx: string;
128
+ prevOutScriptHex: string;
129
+ prevOutValue: string;
130
+ fallbackLeafScriptHex: string;
131
+ }
132
+
133
+ /**
134
+ * A member's standalone BIP-340 signature over the fallback script-path sighash.
135
+ * `signerPk` is the member's x-only key (which CHECKSIGADD slot it satisfies).
136
+ */
137
+ export interface FallbackSignatureBody {
138
+ cohortId: string;
139
+ sessionId: string;
140
+ signerPk: Uint8Array;
141
+ fallbackSignature: Uint8Array;
142
+ }
143
+
103
144
  // ── Narrow message types (BaseMessage & { type, body }) ──────────────────
104
145
 
105
146
  export type CohortAdvertMessage = BaseMessage & { type: typeof COHORT_ADVERT; body: CohortAdvertBody };
@@ -107,12 +148,15 @@ export type CohortOptInMessage = BaseMessage & { type: typeof COHORT_OPT_IN; bod
107
148
  export type CohortOptInAcceptMessage = BaseMessage & { type: typeof COHORT_OPT_IN_ACCEPT; body: CohortOptInAcceptBody };
108
149
  export type CohortReadyMessage = BaseMessage & { type: typeof COHORT_READY; body: CohortReadyBody };
109
150
  export type SubmitUpdateMessage = BaseMessage & { type: typeof SUBMIT_UPDATE; body: SubmitUpdateBody };
151
+ export type SubmitNonIncludedMessage = BaseMessage & { type: typeof SUBMIT_NONINCLUDED; body: SubmitNonIncludedBody };
110
152
  export type DistributeAggregatedDataMessage = BaseMessage & { type: typeof DISTRIBUTE_AGGREGATED_DATA; body: DistributeAggregatedDataBody };
111
153
  export type ValidationAckMessage = BaseMessage & { type: typeof VALIDATION_ACK; body: ValidationAckBody };
112
154
  export type AuthorizationRequestMessage = BaseMessage & { type: typeof AUTHORIZATION_REQUEST; body: AuthorizationRequestBody };
113
155
  export type NonceContributionMessage = BaseMessage & { type: typeof NONCE_CONTRIBUTION; body: NonceContributionBody };
114
156
  export type AggregatedNonceMessage = BaseMessage & { type: typeof AGGREGATED_NONCE; body: AggregatedNonceBody };
115
157
  export type SignatureAuthorizationMessage = BaseMessage & { type: typeof SIGNATURE_AUTHORIZATION; body: SignatureAuthorizationBody };
158
+ export type FallbackAuthorizationRequestMessage = BaseMessage & { type: typeof FALLBACK_AUTHORIZATION_REQUEST; body: FallbackAuthorizationRequestBody };
159
+ export type FallbackSignatureMessage = BaseMessage & { type: typeof FALLBACK_SIGNATURE; body: FallbackSignatureBody };
116
160
 
117
161
  /** Discriminated union of every well-formed aggregation message. */
118
162
  export type AggregationMessage =
@@ -121,12 +165,15 @@ export type AggregationMessage =
121
165
  | CohortOptInAcceptMessage
122
166
  | CohortReadyMessage
123
167
  | SubmitUpdateMessage
168
+ | SubmitNonIncludedMessage
124
169
  | DistributeAggregatedDataMessage
125
170
  | ValidationAckMessage
126
171
  | AuthorizationRequestMessage
127
172
  | NonceContributionMessage
128
173
  | AggregatedNonceMessage
129
- | SignatureAuthorizationMessage;
174
+ | SignatureAuthorizationMessage
175
+ | FallbackAuthorizationRequestMessage
176
+ | FallbackSignatureMessage;
130
177
 
131
178
  // ── Type guards ───────────────────────────────────────────────────────────
132
179
  // Each guard validates `type` plus required body fields so it's safe to use
@@ -144,6 +191,16 @@ const optIntMin = (b: unknown, k: string, min: number): boolean => {
144
191
  const v = b ? (b as Record<string, unknown>)[k] : undefined;
145
192
  return v === undefined || (typeof v === 'number' && Number.isInteger(v) && v >= min);
146
193
  };
194
+ /** Present, an integer, and within [min, max] inclusive. */
195
+ const intInRange = (b: unknown, k: string, min: number, max: number): boolean => {
196
+ const v = b ? (b as Record<string, unknown>)[k] : undefined;
197
+ return typeof v === 'number' && Number.isInteger(v) && v >= min && v <= max;
198
+ };
199
+ /** Absent, or present as a string in the allowed set. */
200
+ const optStrOneOf = (b: unknown, k: string, allowed: readonly string[]): boolean => {
201
+ const v = b ? (b as Record<string, unknown>)[k] : undefined;
202
+ return v === undefined || (typeof v === 'string' && allowed.includes(v));
203
+ };
147
204
  const hasBool = (b: unknown, k: string): boolean =>
148
205
  !!b && typeof (b as Record<string, unknown>)[k] === 'boolean';
149
206
  const hasBytes = (b: unknown, k: string): boolean =>
@@ -164,6 +221,20 @@ export function isCohortAdvertMessage(m: BaseMessage): m is CohortAdvertMessage
164
221
  && optIntMin(m.body, 'maxParticipants', 1)
165
222
  && hasStr(m.body, 'beaconType')
166
223
  && hasStr(m.body, 'network')
224
+ // Recovery params are mandatory: a participant must see the recovery terms
225
+ // (key + timelock) before funding the beacon UTXO (ADR 042). recoverySequence
226
+ // is range-checked here because the participant funds based on the advert and
227
+ // does not separately run validateCohortConditions: an out-of-range value
228
+ // (e.g. one with the BIP-68 disable bit set) must be rejected before funding.
229
+ && hasStr(m.body, 'recoveryKey')
230
+ && intInRange(m.body, 'recoverySequence', 1, MAX_RECOVERY_SEQUENCE)
231
+ // fundingModel is optional on the wire (absent means the operator-funded
232
+ // default), but when present it must name a known model.
233
+ && optStrOneOf(m.body, 'fundingModel', KNOWN_FUNDING_MODELS)
234
+ // fallbackThreshold is optional (absent means n-1 at keygen); when present it
235
+ // must be a positive integer. The upper bound against the cohort size is
236
+ // checked when the participant recomputes the beacon address.
237
+ && optIntMin(m.body, 'fallbackThreshold', 1)
167
238
  && hasBytes(m.body, 'communicationPk');
168
239
  }
169
240
 
@@ -191,6 +262,10 @@ export function isSubmitUpdateMessage(m: BaseMessage): m is SubmitUpdateMessage
191
262
  && !!m.body && typeof (m.body as Record<string, unknown>).signedUpdate === 'object';
192
263
  }
193
264
 
265
+ export function isSubmitNonIncludedMessage(m: BaseMessage): m is SubmitNonIncludedMessage {
266
+ return m.type === SUBMIT_NONINCLUDED && hasStr(m.body, 'cohortId');
267
+ }
268
+
194
269
  export function isDistributeAggregatedDataMessage(m: BaseMessage): m is DistributeAggregatedDataMessage {
195
270
  return m.type === DISTRIBUTE_AGGREGATED_DATA
196
271
  && hasStr(m.body, 'cohortId')
@@ -233,3 +308,21 @@ export function isSignatureAuthorizationMessage(m: BaseMessage): m is SignatureA
233
308
  && hasStr(m.body, 'sessionId')
234
309
  && hasBytes(m.body, 'partialSignature');
235
310
  }
311
+
312
+ export function isFallbackAuthorizationRequestMessage(m: BaseMessage): m is FallbackAuthorizationRequestMessage {
313
+ return m.type === FALLBACK_AUTHORIZATION_REQUEST
314
+ && hasStr(m.body, 'cohortId')
315
+ && hasStr(m.body, 'sessionId')
316
+ && hasStr(m.body, 'pendingTx')
317
+ && hasStr(m.body, 'prevOutScriptHex')
318
+ && hasStr(m.body, 'prevOutValue')
319
+ && hasStr(m.body, 'fallbackLeafScriptHex');
320
+ }
321
+
322
+ export function isFallbackSignatureMessage(m: BaseMessage): m is FallbackSignatureMessage {
323
+ return m.type === FALLBACK_SIGNATURE
324
+ && hasStr(m.body, 'cohortId')
325
+ && hasStr(m.body, 'sessionId')
326
+ && hasBytes(m.body, 'signerPk')
327
+ && hasBytes(m.body, 'fallbackSignature');
328
+ }
@@ -7,6 +7,8 @@
7
7
  * - Step 3 (Aggregate & Validate): DISTRIBUTE_AGGREGATED_DATA, VALIDATION_ACK
8
8
  * - Step 4 (Sign & Broadcast): AUTHORIZATION_REQUEST, NONCE_CONTRIBUTION,
9
9
  * AGGREGATED_NONCE, SIGNATURE_AUTHORIZATION
10
+ * - Step 4 fallback (k-of-n script path, ADR 042): FALLBACK_AUTHORIZATION_REQUEST,
11
+ * FALLBACK_SIGNATURE
10
12
  */
11
13
  export const AGGREGATION_MESSAGE_PREFIX = 'https://btcr2.dev/aggregation';
12
14
 
@@ -18,6 +20,8 @@ export const COHORT_READY = `${AGGREGATION_MESSAGE_PREFIX}/keygen/cohort_ready`;
18
20
 
19
21
  // Step 2 + 3: Update Submission, Aggregation, Validation
20
22
  export const SUBMIT_UPDATE = `${AGGREGATION_MESSAGE_PREFIX}/update/submit_update`;
23
+ /** A member with no update this round declines explicitly (cooperative non-inclusion). */
24
+ export const SUBMIT_NONINCLUDED = `${AGGREGATION_MESSAGE_PREFIX}/update/submit_nonincluded`;
21
25
  export const DISTRIBUTE_AGGREGATED_DATA = `${AGGREGATION_MESSAGE_PREFIX}/update/distribute_aggregated_data`;
22
26
  export const VALIDATION_ACK = `${AGGREGATION_MESSAGE_PREFIX}/update/validation_ack`;
23
27
 
@@ -26,3 +30,11 @@ export const AUTHORIZATION_REQUEST = `${AGGREGATION_MESSAGE_PREFIX}/sign/authori
26
30
  export const NONCE_CONTRIBUTION = `${AGGREGATION_MESSAGE_PREFIX}/sign/nonce_contribution`;
27
31
  export const AGGREGATED_NONCE = `${AGGREGATION_MESSAGE_PREFIX}/sign/aggregated_nonce`;
28
32
  export const SIGNATURE_AUTHORIZATION = `${AGGREGATION_MESSAGE_PREFIX}/sign/signature_authorization`;
33
+
34
+ // Step 4 fallback: k-of-n script-path signing when the optimistic n-of-n key
35
+ // path stalls (graceful liveness, ADR 042). A single standalone BIP-340
36
+ // signature per member, no nonce round.
37
+ /** Service asks members to sign the fallback (k-of-n) script path of the beacon tx. */
38
+ export const FALLBACK_AUTHORIZATION_REQUEST = `${AGGREGATION_MESSAGE_PREFIX}/sign/fallback_authorization_request`;
39
+ /** A member returns a standalone BIP-340 signature over the fallback script-path sighash. */
40
+ export const FALLBACK_SIGNATURE = `${AGGREGATION_MESSAGE_PREFIX}/sign/fallback_signature`;
@@ -8,8 +8,11 @@ import {
8
8
  COHORT_OPT_IN_ACCEPT,
9
9
  COHORT_READY,
10
10
  DISTRIBUTE_AGGREGATED_DATA,
11
+ FALLBACK_AUTHORIZATION_REQUEST,
12
+ FALLBACK_SIGNATURE,
11
13
  NONCE_CONTRIBUTION,
12
14
  SIGNATURE_AUTHORIZATION,
15
+ SUBMIT_NONINCLUDED,
13
16
  SUBMIT_UPDATE,
14
17
  VALIDATION_ACK,
15
18
  } from './constants.js';
@@ -102,6 +105,22 @@ export function createSubmitUpdateMessage(fields: SubmitUpdateMessage): BaseMess
102
105
  return new BaseMessage({ type: SUBMIT_UPDATE, from, to, body });
103
106
  }
104
107
 
108
+ type SubmitNonIncludedMessage = {
109
+ from: string;
110
+ to: string;
111
+ cohortId: string;
112
+ };
113
+
114
+ /**
115
+ * Factory for a Submit Non-Included message: a member declares it has no update
116
+ * this round (cooperative non-inclusion). Membership is proven by the signed
117
+ * envelope, so the body carries only the cohortId.
118
+ */
119
+ export function createSubmitNonIncludedMessage(fields: SubmitNonIncludedMessage): BaseMessage {
120
+ const { from, to, ...body } = fields;
121
+ return new BaseMessage({ type: SUBMIT_NONINCLUDED, from, to, body });
122
+ }
123
+
105
124
  /**
106
125
  * Step 3: Aggregate & Validate
107
126
  * Factory functions for creating messages related to the aggregate and validate step, where
@@ -238,3 +257,41 @@ export function createSignatureAuthorizationMessage(fields: SignatureAuthorizati
238
257
  const { from, to, ...body } = fields;
239
258
  return new BaseMessage({ type: SIGNATURE_AUTHORIZATION, from, to, body });
240
259
  }
260
+
261
+ type FallbackAuthorizationRequestMessage = {
262
+ from: string;
263
+ to: string;
264
+ cohortId: string;
265
+ sessionId: string;
266
+ pendingTx: string;
267
+ prevOutScriptHex: string;
268
+ prevOutValue: string;
269
+ fallbackLeafScriptHex: string;
270
+ };
271
+ type FallbackSignatureMessage = {
272
+ from: string;
273
+ to: string;
274
+ cohortId: string;
275
+ sessionId: string;
276
+ signerPk: Uint8Array;
277
+ fallbackSignature: Uint8Array;
278
+ };
279
+
280
+ /**
281
+ * Factory for a Fallback Authorization Request: the service asks members to
282
+ * authorize the k-of-n script-path spend of the beacon transaction when the
283
+ * optimistic n-of-n key path stalls (ADR 042).
284
+ */
285
+ export function createFallbackAuthorizationRequestMessage(fields: FallbackAuthorizationRequestMessage): BaseMessage {
286
+ const { from, to, ...body } = fields;
287
+ return new BaseMessage({ type: FALLBACK_AUTHORIZATION_REQUEST, from, to, body });
288
+ }
289
+
290
+ /**
291
+ * Factory for a Fallback Signature: a member's standalone BIP-340 signature over
292
+ * the fallback script-path sighash (no nonce round).
293
+ */
294
+ export function createFallbackSignatureMessage(fields: FallbackSignatureMessage): BaseMessage {
295
+ const { from, to, ...body } = fields;
296
+ return new BaseMessage({ type: FALLBACK_SIGNATURE, from, to, body });
297
+ }
@@ -6,8 +6,11 @@ import {
6
6
  COHORT_OPT_IN_ACCEPT,
7
7
  COHORT_READY,
8
8
  DISTRIBUTE_AGGREGATED_DATA,
9
+ FALLBACK_AUTHORIZATION_REQUEST,
10
+ FALLBACK_SIGNATURE,
9
11
  NONCE_CONTRIBUTION,
10
12
  SIGNATURE_AUTHORIZATION,
13
+ SUBMIT_NONINCLUDED,
11
14
  SUBMIT_UPDATE,
12
15
  VALIDATION_ACK,
13
16
  } from './constants.js';
@@ -21,6 +24,7 @@ const KEYGEN_VALUES: Set<string> = new Set([
21
24
 
22
25
  const UPDATE_VALUES: Set<string> = new Set([
23
26
  SUBMIT_UPDATE,
27
+ SUBMIT_NONINCLUDED,
24
28
  DISTRIBUTE_AGGREGATED_DATA,
25
29
  VALIDATION_ACK,
26
30
  ]);
@@ -30,6 +34,8 @@ const SIGN_VALUES: Set<string> = new Set([
30
34
  NONCE_CONTRIBUTION,
31
35
  AGGREGATED_NONCE,
32
36
  SIGNATURE_AUTHORIZATION,
37
+ FALLBACK_AUTHORIZATION_REQUEST,
38
+ FALLBACK_SIGNATURE,
33
39
  ]);
34
40
 
35
41
  /**