@did-btcr2/method 0.23.0 → 0.25.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 (160) hide show
  1. package/README.md +96 -50
  2. package/dist/browser.js +36332 -37280
  3. package/dist/browser.mjs +36331 -37279
  4. package/dist/cjs/core/beacon/aggregation/communication/adapter/did-comm.js +1 -1
  5. package/dist/cjs/core/beacon/aggregation/communication/adapter/did-comm.js.map +1 -1
  6. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js +1 -1
  7. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  8. package/dist/cjs/core/beacon/aggregation/coordinator.js +40 -44
  9. package/dist/cjs/core/beacon/aggregation/coordinator.js.map +1 -1
  10. package/dist/cjs/core/beacon/aggregation/participant.js +35 -38
  11. package/dist/cjs/core/beacon/aggregation/participant.js.map +1 -1
  12. package/dist/cjs/core/beacon/aggregation/session/index.js +3 -4
  13. package/dist/cjs/core/beacon/aggregation/session/index.js.map +1 -1
  14. package/dist/cjs/core/beacon/beacon.js.map +1 -1
  15. package/dist/cjs/core/beacon/cas-beacon.js +119 -7
  16. package/dist/cjs/core/beacon/cas-beacon.js.map +1 -1
  17. package/dist/cjs/core/beacon/factory.js +1 -1
  18. package/dist/cjs/core/beacon/factory.js.map +1 -1
  19. package/dist/cjs/core/beacon/{singleton.js → singleton-beacon.js} +19 -27
  20. package/dist/cjs/core/beacon/singleton-beacon.js.map +1 -0
  21. package/dist/cjs/core/beacon/smt-beacon.js +1 -1
  22. package/dist/cjs/core/beacon/smt-beacon.js.map +1 -1
  23. package/dist/cjs/core/identifier.js +1 -1
  24. package/dist/cjs/core/identifier.js.map +1 -1
  25. package/dist/{esm/core/resolve.js → cjs/core/resolver.js} +244 -92
  26. package/dist/cjs/core/resolver.js.map +1 -0
  27. package/dist/cjs/core/update.js +7 -7
  28. package/dist/cjs/core/update.js.map +1 -1
  29. package/dist/cjs/did-btcr2.js +34 -94
  30. package/dist/cjs/did-btcr2.js.map +1 -1
  31. package/dist/cjs/index.js +2 -3
  32. package/dist/cjs/index.js.map +1 -1
  33. package/dist/cjs/utils/did-document.js +9 -19
  34. package/dist/cjs/utils/did-document.js.map +1 -1
  35. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js +1 -1
  36. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js.map +1 -1
  37. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +1 -1
  38. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  39. package/dist/esm/core/beacon/aggregation/coordinator.js +40 -44
  40. package/dist/esm/core/beacon/aggregation/coordinator.js.map +1 -1
  41. package/dist/esm/core/beacon/aggregation/participant.js +35 -38
  42. package/dist/esm/core/beacon/aggregation/participant.js.map +1 -1
  43. package/dist/esm/core/beacon/aggregation/session/index.js +3 -4
  44. package/dist/esm/core/beacon/aggregation/session/index.js.map +1 -1
  45. package/dist/esm/core/beacon/beacon.js.map +1 -1
  46. package/dist/esm/core/beacon/cas-beacon.js +119 -7
  47. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  48. package/dist/esm/core/beacon/factory.js +1 -1
  49. package/dist/esm/core/beacon/factory.js.map +1 -1
  50. package/dist/esm/core/beacon/{singleton.js → singleton-beacon.js} +19 -27
  51. package/dist/esm/core/beacon/singleton-beacon.js.map +1 -0
  52. package/dist/esm/core/beacon/smt-beacon.js +1 -1
  53. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  54. package/dist/esm/core/identifier.js +1 -1
  55. package/dist/esm/core/identifier.js.map +1 -1
  56. package/dist/{cjs/core/resolve.js → esm/core/resolver.js} +244 -92
  57. package/dist/esm/core/resolver.js.map +1 -0
  58. package/dist/esm/core/update.js +7 -7
  59. package/dist/esm/core/update.js.map +1 -1
  60. package/dist/esm/did-btcr2.js +34 -94
  61. package/dist/esm/did-btcr2.js.map +1 -1
  62. package/dist/esm/index.js +2 -3
  63. package/dist/esm/index.js.map +1 -1
  64. package/dist/esm/utils/did-document.js +9 -19
  65. package/dist/esm/utils/did-document.js.map +1 -1
  66. package/dist/types/core/beacon/aggregation/cohort/index.d.ts +1 -0
  67. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts +1 -0
  68. package/dist/types/core/beacon/aggregation/cohort/messages/constants.d.ts +1 -0
  69. package/dist/types/core/beacon/aggregation/cohort/messages/index.d.ts +1 -0
  70. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts +1 -0
  71. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts +2 -2
  72. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts.map +1 -1
  73. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts +1 -0
  74. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts +1 -0
  75. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts +1 -0
  76. package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts +1 -0
  77. package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts +1 -0
  78. package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts +1 -0
  79. package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts +1 -0
  80. package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts +1 -0
  81. package/dist/types/core/beacon/aggregation/cohort/status.d.ts +1 -0
  82. package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts +4 -3
  83. package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts.map +1 -1
  84. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts +5 -3
  85. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +1 -1
  86. package/dist/types/core/beacon/aggregation/communication/error.d.ts +1 -0
  87. package/dist/types/core/beacon/aggregation/communication/factory.d.ts +1 -0
  88. package/dist/types/core/beacon/aggregation/communication/service.d.ts +3 -2
  89. package/dist/types/core/beacon/aggregation/communication/service.d.ts.map +1 -1
  90. package/dist/types/core/beacon/aggregation/coordinator.d.ts +1 -0
  91. package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +1 -1
  92. package/dist/types/core/beacon/aggregation/participant.d.ts +1 -0
  93. package/dist/types/core/beacon/aggregation/participant.d.ts.map +1 -1
  94. package/dist/types/core/beacon/aggregation/session/index.d.ts +1 -0
  95. package/dist/types/core/beacon/aggregation/session/index.d.ts.map +1 -1
  96. package/dist/types/core/beacon/aggregation/session/status.d.ts +1 -0
  97. package/dist/types/core/beacon/beacon.d.ts +10 -4
  98. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  99. package/dist/types/core/beacon/cas-beacon.d.ts +27 -7
  100. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  101. package/dist/types/core/beacon/error.d.ts +1 -0
  102. package/dist/types/core/beacon/factory.d.ts +1 -0
  103. package/dist/types/core/beacon/interfaces.d.ts +1 -0
  104. package/dist/types/core/beacon/signal-discovery.d.ts +1 -0
  105. package/dist/types/core/beacon/{singleton.d.ts → singleton-beacon.d.ts} +7 -5
  106. package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -0
  107. package/dist/types/core/beacon/smt-beacon.d.ts +5 -3
  108. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  109. package/dist/types/core/beacon/utils.d.ts +1 -0
  110. package/dist/types/core/identifier.d.ts +1 -0
  111. package/dist/types/core/interfaces.d.ts +6 -15
  112. package/dist/types/core/interfaces.d.ts.map +1 -1
  113. package/dist/types/core/resolver.d.ts +167 -0
  114. package/dist/types/core/resolver.d.ts.map +1 -0
  115. package/dist/types/core/types.d.ts +1 -0
  116. package/dist/types/core/update.d.ts +4 -3
  117. package/dist/types/core/update.d.ts.map +1 -1
  118. package/dist/types/did-btcr2.d.ts +17 -16
  119. package/dist/types/did-btcr2.d.ts.map +1 -1
  120. package/dist/types/index.d.ts +3 -3
  121. package/dist/types/index.d.ts.map +1 -1
  122. package/dist/types/utils/appendix.d.ts +1 -0
  123. package/dist/types/utils/did-document-builder.d.ts +1 -0
  124. package/dist/types/utils/did-document.d.ts +2 -6
  125. package/dist/types/utils/did-document.d.ts.map +1 -1
  126. package/package.json +5 -5
  127. package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.ts +1 -1
  128. package/src/core/beacon/aggregation/communication/adapter/did-comm.ts +4 -3
  129. package/src/core/beacon/aggregation/communication/adapter/nostr.ts +4 -3
  130. package/src/core/beacon/aggregation/communication/service.ts +2 -2
  131. package/src/core/beacon/aggregation/coordinator.ts +40 -44
  132. package/src/core/beacon/aggregation/participant.ts +38 -40
  133. package/src/core/beacon/aggregation/session/index.ts +3 -4
  134. package/src/core/beacon/beacon.ts +9 -5
  135. package/src/core/beacon/cas-beacon.ts +156 -10
  136. package/src/core/beacon/factory.ts +1 -1
  137. package/src/core/beacon/{singleton.ts → singleton-beacon.ts} +20 -36
  138. package/src/core/beacon/smt-beacon.ts +4 -3
  139. package/src/core/identifier.ts +1 -1
  140. package/src/core/interfaces.ts +5 -16
  141. package/src/core/resolver.ts +706 -0
  142. package/src/core/update.ts +9 -9
  143. package/src/did-btcr2.ts +37 -130
  144. package/src/index.ts +2 -3
  145. package/src/utils/did-document.ts +10 -18
  146. package/dist/cjs/core/beacon/singleton.js.map +0 -1
  147. package/dist/cjs/core/resolve.js.map +0 -1
  148. package/dist/cjs/utils/general.js +0 -195
  149. package/dist/cjs/utils/general.js.map +0 -1
  150. package/dist/esm/core/beacon/singleton.js.map +0 -1
  151. package/dist/esm/core/resolve.js.map +0 -1
  152. package/dist/esm/utils/general.js +0 -195
  153. package/dist/esm/utils/general.js.map +0 -1
  154. package/dist/types/core/beacon/singleton.d.ts.map +0 -1
  155. package/dist/types/core/resolve.d.ts +0 -92
  156. package/dist/types/core/resolve.d.ts.map +0 -1
  157. package/dist/types/utils/general.d.ts +0 -85
  158. package/dist/types/utils/general.d.ts.map +0 -1
  159. package/src/core/resolve.ts +0 -474
  160. package/src/utils/general.ts +0 -204
@@ -1,4 +1,4 @@
1
- import { KeyBytes, Logger, Maybe } from '@did-btcr2/common';
1
+ import { KeyBytes, Maybe } from '@did-btcr2/common';
2
2
  import { HDKey } from '@scure/bip32';
3
3
  import { mnemonicToSeedSync } from '@scure/bip39';
4
4
  import * as musig2 from '@scure/btc-signer/musig2';
@@ -130,7 +130,7 @@ export class BeaconParticipant {
130
130
  this.protocol = protocol || new NostrAdapter();
131
131
  this.protocol.setKeys({ public: pk, secret });
132
132
  this.cohortKeyState.set('__UNSET__', this.beaconKeyIndex);
133
- Logger.debug(`BeaconParticipant initialized with DID: ${this.did}, Name: ${this.name}, Key Index: ${this.beaconKeyIndex}`);
133
+ console.debug(`BeaconParticipant initialized with DID: ${this.did}, Name: ${this.name}, Key Index: ${this.beaconKeyIndex}`);
134
134
  }
135
135
 
136
136
  /**
@@ -138,7 +138,7 @@ export class BeaconParticipant {
138
138
  * @returns {void}
139
139
  */
140
140
  public start(): void {
141
- Logger.info(`Setting up BeaconParticipant ${this.name} (${this.did}) on ${this.protocol.name} ...`);
141
+ console.info(`Setting up BeaconParticipant ${this.name} (${this.did}) on ${this.protocol.name} ...`);
142
142
  this.protocol.registerMessageHandler(BEACON_COHORT_ADVERT, this._handleCohortAdvert.bind(this));
143
143
  this.protocol.registerMessageHandler(BEACON_COHORT_OPT_IN_ACCEPT, this._handleSubscribeAccept.bind(this));
144
144
  this.protocol.registerMessageHandler(BEACON_COHORT_READY, this._handleCohortReady.bind(this));
@@ -171,10 +171,10 @@ export class BeaconParticipant {
171
171
  this.beaconKeyIndex = this.cohortKeyState.size + 1;
172
172
  }
173
173
  if(this.cohortKeyState.has(cohortId)) {
174
- Logger.warn(`Cohort key state for cohort ${cohortId} already exists. Updating key index.`);
174
+ console.warn(`Cohort key state for cohort ${cohortId} already exists. Updating key index.`);
175
175
  }
176
176
  this.cohortKeyState.set(cohortId, this.beaconKeyIndex);
177
- Logger.info(`Cohort key state updated. Next beacon key index: ${this.beaconKeyIndex + 1}`);
177
+ console.info(`Cohort key state updated. Next beacon key index: ${this.beaconKeyIndex + 1}`);
178
178
  }
179
179
 
180
180
  /**
@@ -196,7 +196,7 @@ export class BeaconParticipant {
196
196
  }
197
197
 
198
198
  if (this.cohortKeyState.has(cohortId)) {
199
- Logger.warn(`Cohort key state already exists for ${cohortId}. Skipping migration from '__UNSET__'.`);
199
+ console.warn(`Cohort key state already exists for ${cohortId}. Skipping migration from '__UNSET__'.`);
200
200
  this.cohortKeyState.delete(unsetKey);
201
201
  return;
202
202
  }
@@ -204,7 +204,7 @@ export class BeaconParticipant {
204
204
  this.setCohortKey(cohortId);
205
205
  this.cohortKeyState.delete(unsetKey);
206
206
 
207
- Logger.info(`Finalized '__UNSET__' CohortKeyState with ${cohortId} for ${this.did}`);
207
+ console.info(`Finalized '__UNSET__' CohortKeyState with ${cohortId} for ${this.did}`);
208
208
  }
209
209
 
210
210
  /**
@@ -226,25 +226,25 @@ export class BeaconParticipant {
226
226
  * @returns {Promise<void>}
227
227
  */
228
228
  public async _handleCohortAdvert(message: Maybe<CohortAdvertMessage>): Promise<void> {
229
- Logger.debug('_handleCohortAdvert', message);
229
+ console.debug('_handleCohortAdvert', message);
230
230
  const cohortAdvertMessage = BeaconCohortAdvertMessage.fromJSON(message);
231
- Logger.info(`Received new cohort announcement from ${cohortAdvertMessage.from}`, cohortAdvertMessage);
231
+ console.info(`Received new cohort announcement from ${cohortAdvertMessage.from}`, cohortAdvertMessage);
232
232
 
233
233
  const cohortId = cohortAdvertMessage.body?.cohortId;
234
234
  if (!cohortId) {
235
- Logger.warn('Received malformed cohort advert message: missing cohortId', cohortAdvertMessage);
235
+ console.warn('Received malformed cohort advert message: missing cohortId', cohortAdvertMessage);
236
236
  return;
237
237
  }
238
238
 
239
239
  const network = cohortAdvertMessage.body?.network;
240
240
  if (!network) {
241
- Logger.warn('Received malformed cohort advert message: missing network', cohortAdvertMessage);
241
+ console.warn('Received malformed cohort advert message: missing network', cohortAdvertMessage);
242
242
  return;
243
243
  }
244
244
 
245
245
  const minParticipants = cohortAdvertMessage.body?.cohortSize;
246
246
  if (!cohortId || !network || !minParticipants) {
247
- Logger.warn('Received malformed cohort advert message: missing minParticipants', cohortAdvertMessage);
247
+ console.warn('Received malformed cohort advert message: missing minParticipants', cohortAdvertMessage);
248
248
  return;
249
249
  }
250
250
 
@@ -271,30 +271,30 @@ export class BeaconParticipant {
271
271
  const cohortId = cohortSetMessage.body?.cohortId;
272
272
  const cohort = this.cohorts.find(c => c.id === cohortId);
273
273
  if (!cohortId || !cohort) {
274
- Logger.warn(`Cohort with ID ${cohortId} not found or not joined by participant ${this.did}.`);
274
+ console.warn(`Cohort with ID ${cohortId} not found or not joined by participant ${this.did}.`);
275
275
  return;
276
276
  }
277
277
  this.finalizeUnsetCohortKey(cohortId);
278
278
  const participantPkBytes = this.getCohortKey(cohortId).publicKey;
279
279
  if(!participantPkBytes) {
280
- Logger.error(`Failed to derive public key for cohort ${cohortId}`);
280
+ console.error(`Failed to derive public key for cohort ${cohortId}`);
281
281
  return;
282
282
  }
283
283
  const participantPk = Buffer.from(participantPkBytes).toString('hex');
284
284
  const beaconAddress = cohortSetMessage.body?.beaconAddress;
285
285
  if(!beaconAddress) {
286
- Logger.error(`Beacon address not provided in cohort set message for ${cohortId}`);
286
+ console.error(`Beacon address not provided in cohort set message for ${cohortId}`);
287
287
  return;
288
288
  }
289
289
  const cohortKeys = cohortSetMessage.body?.cohortKeys;
290
290
  if(!cohortKeys) {
291
- Logger.error(`Cohort keys not provided in cohort set message for ${cohortId}`);
291
+ console.error(`Cohort keys not provided in cohort set message for ${cohortId}`);
292
292
  return;
293
293
  }
294
294
  const keys = cohortKeys.map(key => Buffer.from(key).toString('hex'));
295
295
  cohort.validateCohort([participantPk], keys, beaconAddress);
296
- Logger.info(`BeaconParticipant w/ pk ${participantPk} successfully joined cohort ${cohortId} with beacon address ${beaconAddress}.`);
297
- Logger.info(`Cohort status: ${cohort.status}`);
296
+ console.info(`BeaconParticipant w/ pk ${participantPk} successfully joined cohort ${cohortId} with beacon address ${beaconAddress}.`);
297
+ console.info(`Cohort status: ${cohort.status}`);
298
298
  }
299
299
 
300
300
  /**
@@ -306,17 +306,17 @@ export class BeaconParticipant {
306
306
  const authRequest = BeaconCohortAuthorizationRequestMessage.fromJSON(message);
307
307
  const cohort = this.cohorts.find(c => c.id === authRequest.body?.cohortId);
308
308
  if (!cohort) {
309
- Logger.warn(`Authorization request for unknown cohort ${authRequest.body?.cohortId} from ${authRequest.from}`);
309
+ console.warn(`Authorization request for unknown cohort ${authRequest.body?.cohortId} from ${authRequest.from}`);
310
310
  return;
311
311
  }
312
312
  const id = authRequest.body?.sessionId;
313
313
  if (!id) {
314
- Logger.warn(`Authorization request missing session ID from ${authRequest.from}`);
314
+ console.warn(`Authorization request missing session ID from ${authRequest.from}`);
315
315
  return;
316
316
  }
317
317
  const pendingTx = authRequest.body?.pendingTx;
318
318
  if (!pendingTx) {
319
- Logger.warn(`Authorization request missing pending transaction from ${authRequest.from}`);
319
+ console.warn(`Authorization request missing pending transaction from ${authRequest.from}`);
320
320
  return;
321
321
  }
322
322
  const session = new BeaconCohortSigningSession({
@@ -338,23 +338,23 @@ export class BeaconParticipant {
338
338
  const aggNonceMessage = BeaconCohortAggregatedNonceMessage.fromJSON(message);
339
339
  const sessionId = aggNonceMessage.body?.sessionId;
340
340
  if (!sessionId) {
341
- Logger.warn(`Aggregated nonce message missing session ID from ${aggNonceMessage.from}`);
341
+ console.warn(`Aggregated nonce message missing session ID from ${aggNonceMessage.from}`);
342
342
  return;
343
343
  }
344
344
  const session = this.activeSigningSessions.get(sessionId);
345
345
  if (!session) {
346
- Logger.warn(`Aggregated nonce message received for unknown session ${sessionId}`);
346
+ console.warn(`Aggregated nonce message received for unknown session ${sessionId}`);
347
347
  return;
348
348
  }
349
349
  const aggregatedNonce = aggNonceMessage.body?.aggregatedNonce;
350
350
  if (!aggregatedNonce) {
351
- Logger.warn(`Aggregated nonce message missing aggregated nonce from ${aggNonceMessage.from}`);
351
+ console.warn(`Aggregated nonce message missing aggregated nonce from ${aggNonceMessage.from}`);
352
352
  return;
353
353
  }
354
354
  session.aggregatedNonce = aggregatedNonce;
355
355
  const participantSk = this.getCohortKey(session.cohort.id).privateKey;
356
356
  if(!participantSk) {
357
- Logger.error(`Failed to derive secret key for cohort ${session.cohort.id}`);
357
+ console.error(`Failed to derive secret key for cohort ${session.cohort.id}`);
358
358
  return;
359
359
  }
360
360
  const partialSig = session.generatePartialSignature(participantSk);
@@ -368,7 +368,7 @@ export class BeaconParticipant {
368
368
  */
369
369
  public async subscribeToCoordinator(coordinatorDid: string): Promise<any> {
370
370
  if(this.coordinatorDids.includes(coordinatorDid)) {
371
- Logger.info(`Already subscribed to coordinator ${coordinatorDid}`);
371
+ console.info(`Already subscribed to coordinator ${coordinatorDid}`);
372
372
  return;
373
373
  }
374
374
  const subMessage = new BeaconCohortSubscribeMessage({ to: coordinatorDid, from: this.did });
@@ -382,16 +382,16 @@ export class BeaconParticipant {
382
382
  * @returns {Promise<void>}
383
383
  */
384
384
  public async joinCohort(cohortId: string, coordinatorDid: string): Promise<void> {
385
- Logger.info(`BeaconParticipant ${this.did} joining cohort ${cohortId} with coordinator ${coordinatorDid}`);
385
+ console.info(`BeaconParticipant ${this.did} joining cohort ${cohortId} with coordinator ${coordinatorDid}`);
386
386
  this.finalizeUnsetCohortKey(cohortId);
387
387
  const cohort = this.cohorts.find(c => c.id === cohortId);
388
388
  if (!cohort) {
389
- Logger.warn(`Cohort with ID ${cohortId} not found.`);
389
+ console.warn(`Cohort with ID ${cohortId} not found.`);
390
390
  return;
391
391
  }
392
392
  const pk = this.getCohortKey(cohortId).publicKey;
393
393
  if(!pk) {
394
- Logger.error(`Failed to derive public key for cohort ${cohortId} at index ${this.beaconKeyIndex}`);
394
+ console.error(`Failed to derive public key for cohort ${cohortId} at index ${this.beaconKeyIndex}`);
395
395
  return;
396
396
  }
397
397
  this.setCohortKey(cohortId);
@@ -415,11 +415,11 @@ export class BeaconParticipant {
415
415
  public async requestCohortSignature(cohortId: string, data: string): Promise<boolean> {
416
416
  const cohort = this.cohorts.find(c => c.id === cohortId);
417
417
  if (!cohort) {
418
- Logger.warn(`Cohort with ID ${cohortId} not found.`);
418
+ console.warn(`Cohort with ID ${cohortId} not found.`);
419
419
  return false;
420
420
  }
421
421
  if(cohort.status !== COHORT_STATUS.COHORT_SET_STATUS) {
422
- Logger.warn(`Cohort ${cohortId} not in a set state. Current status: ${cohort.status}`);
422
+ console.warn(`Cohort ${cohortId} not in a set state. Current status: ${cohort.status}`);
423
423
  return false;
424
424
  }
425
425
  const reqSigMessage = new BeaconCohortRequestSignatureMessage({
@@ -469,16 +469,14 @@ export class BeaconParticipant {
469
469
  session: BeaconCohortSigningSession
470
470
  ): Promise<void> {
471
471
  const nonceContributionMessage = BeaconCohortNonceContributionMessage.fromJSON({
472
- to : cohort.coordinatorDid,
473
- from : this.did,
474
- body : {
475
- sessionId : session.id,
476
- cohortId : cohort.id,
477
- nonceContribution
478
- }
472
+ to : cohort.coordinatorDid,
473
+ from : this.did,
474
+ sessionId : session.id,
475
+ cohortId : cohort.id,
476
+ nonceContribution
479
477
  });
480
478
  await this.protocol.sendMessage(nonceContributionMessage, this.did, cohort.coordinatorDid);
481
- Logger.info(`Nonce contribution sent for session ${session.id} in cohort ${cohort.id} by participant ${this.did}`);
479
+ console.info(`Nonce contribution sent for session ${session.id} in cohort ${cohort.id} by participant ${this.did}`);
482
480
  }
483
481
 
484
482
  /**
@@ -496,7 +494,7 @@ export class BeaconParticipant {
496
494
  partialSignature : partialSig,
497
495
  });
498
496
  await this.protocol.sendMessage(sigAuthMessage, this.did, session.cohort.coordinatorDid);
499
- Logger.info(`Partial signature sent for session ${session.id} in cohort ${session.cohort.id} by participant ${this.did}`);
497
+ console.info(`Partial signature sent for session ${session.id} in cohort ${session.cohort.id} by participant ${this.did}`);
500
498
  }
501
499
 
502
500
  /**
@@ -1,4 +1,3 @@
1
- import { Logger } from '@did-btcr2/common';
2
1
  import * as musig2 from '@scure/btc-signer/musig2';
3
2
  import { Transaction } from 'bitcoinjs-lib';
4
3
  import { AggregateBeaconError } from '../../error.js';
@@ -166,7 +165,7 @@ export class BeaconCohortSigningSession implements SigningSession {
166
165
  }
167
166
 
168
167
  if (this.nonceContributions.get(from)) {
169
- Logger.warn(`WARNING: Nonce contribution already received from ${from}.`);
168
+ console.warn(`WARNING: Nonce contribution already received from ${from}.`);
170
169
  }
171
170
 
172
171
  this.nonceContributions.set(from, nonceContribution);
@@ -210,7 +209,7 @@ export class BeaconCohortSigningSession implements SigningSession {
210
209
  }
211
210
 
212
211
  if(this.partialSignatures.get(from)) {
213
- Logger.warn(`WARNING: Partial signature already received from ${from}.`);
212
+ console.warn(`WARNING: Partial signature already received from ${from}.`);
214
213
  }
215
214
 
216
215
  this.partialSignatures.set(from, partialSignature);
@@ -236,7 +235,7 @@ export class BeaconCohortSigningSession implements SigningSession {
236
235
  }
237
236
 
238
237
  const sigSum = [...this.partialSignatures.values()].reduce((sum, sig) => sum + bigEndianToInt(sig), 0n);
239
- Logger.info(`Aggregated Signature computed: ${sigSum}`);
238
+ console.info(`Aggregated Signature computed: ${sigSum}`);
240
239
 
241
240
  this.aggregatedNonce ??= this.generateAggregatedNonce();
242
241
 
@@ -1,8 +1,9 @@
1
1
  import { KeyBytes } from '@did-btcr2/common';
2
2
  import { BitcoinConnection } from '@did-btcr2/bitcoin';
3
- import { SignedBTCR2Update } from '../../../../cryptosuite/dist/types/data-integrity-proof/interface.js';
3
+ import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
4
+ import type { BeaconProcessResult } from '../resolver.js';
4
5
  import { SidecarData } from '../types.js';
5
- import { BeaconService, BeaconSignal, BlockMetadata } from './interfaces.js';
6
+ import { BeaconService, BeaconSignal } from './interfaces.js';
6
7
 
7
8
  /**
8
9
  * Abstract base class for all BTCR2 Beacon types.
@@ -32,15 +33,18 @@ export abstract class Beacon {
32
33
  /**
33
34
  * Processes an array of Beacon Signals to extract BTCR2 Signed Updates.
34
35
  * Used during the resolve path.
36
+ *
37
+ * Returns successfully resolved updates and any data needs that must be
38
+ * satisfied before remaining signals can be processed.
39
+ *
35
40
  * @param {Array<BeaconSignal>} signals The beacon signals discovered on-chain.
36
41
  * @param {SidecarData} sidecar The processed sidecar data containing update/CAS/SMT maps.
37
- * @returns {Promise<Array<[SignedBTCR2Update, BlockMetadata]>>} The updates announced by the signals.
42
+ * @returns {BeaconProcessResult} The updates and any data needs.
38
43
  */
39
44
  abstract processSignals(
40
45
  signals: Array<BeaconSignal>,
41
46
  sidecar: SidecarData,
42
- ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>>;
43
-
47
+ ): BeaconProcessResult;
44
48
 
45
49
  /**
46
50
  * Broadcasts a signed update as a Beacon Signal to the Bitcoin network.
@@ -1,6 +1,9 @@
1
- import { BitcoinConnection } from '@did-btcr2/bitcoin';
2
- import { KeyBytes } from '@did-btcr2/common';
1
+ import { AddressUtxo, BitcoinConnection } from '@did-btcr2/bitcoin';
2
+ import { canonicalHash, canonicalize, decode, encode, hash, KeyBytes } from '@did-btcr2/common';
3
3
  import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
4
+ import { SchnorrKeyPair } from '@did-btcr2/keypair';
5
+ import { opcodes, Psbt, script } from 'bitcoinjs-lib';
6
+ import type { BeaconProcessResult, DataNeed } from '../resolver.js';
4
7
  import { SidecarData } from '../types.js';
5
8
  import { Beacon } from './beacon.js';
6
9
  import { CASBeaconError } from './error.js';
@@ -8,6 +11,13 @@ import { BeaconService, BeaconSignal, BlockMetadata } from './interfaces.js';
8
11
 
9
12
  /**
10
13
  * Implements {@link https://dcdpr.github.io/did-btcr2/terminology.html#cas-beacon | CAS Beacon}.
14
+ *
15
+ * A CAS (Content-Addressed Store) Beacon aggregates updates for multiple DIDs
16
+ * into a single CAS Announcement — a mapping of DIDs to their update hashes.
17
+ * The hash of the CAS Announcement is broadcast on-chain via OP_RETURN.
18
+ * During resolution, the CAS Announcement is retrieved from the sidecar (or CAS)
19
+ * and used to look up the individual signed update for the DID being resolved.
20
+ *
11
21
  * @class CASBeacon
12
22
  * @type {CASBeacon}
13
23
  * @extends {Beacon}
@@ -23,31 +33,167 @@ export class CASBeacon extends Beacon {
23
33
 
24
34
  /**
25
35
  * Implements {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process-cas-beacon | 7.2.e.1 Process CAS Beacon}.
36
+ *
37
+ * For each signal, the signalBytes contain the hex-encoded hash of a CAS Announcement.
38
+ * The CAS Announcement maps DIDs to their base64url-encoded update hashes.
39
+ * This method looks up the CAS Announcement from the sidecar, extracts the update
40
+ * hash for the DID being resolved, and retrieves the corresponding signed update.
41
+ *
26
42
  * @param {Array<BeaconSignal>} signals The array of Beacon Signals to process.
27
43
  * @param {SidecarData} sidecar The sidecar data associated with the CAS Beacon.
28
- * @returns {Promise<Array<[SignedBTCR2Update, BlockMetadata]>>} The processed signals.
29
- * @throws {CASBeaconError} if processing fails.
44
+ * @returns {BeaconProcessResult} Successfully resolved updates and any data needs.
45
+ * @throws {CASBeaconError} if hash verification fails (validation errors only).
30
46
  */
31
47
  processSignals(
32
48
  signals: Array<BeaconSignal>,
33
49
  sidecar: SidecarData
34
- ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>> {
35
- throw new CASBeaconError('Method not implemented.', `METHOD_NOT_IMPLEMENTED`, { signals, sidecar });
50
+ ): BeaconProcessResult {
51
+ const updates = new Array<[SignedBTCR2Update, BlockMetadata]>();
52
+ const needs = new Array<DataNeed>();
53
+
54
+ // Extract the DID from the beacon service id (strip the #fragment)
55
+ const did = this.service.id.split('#')[0];
56
+
57
+ for(const signal of signals) {
58
+ // Decode signal bytes from hex and re-encode to base64url for sidecar lookup
59
+ const announcementHash = encode(decode(signal.signalBytes, 'hex'));
60
+
61
+ // Look up the CAS Announcement in sidecar casMap
62
+ const casAnnouncement = sidecar.casMap.get(announcementHash);
63
+
64
+ if(!casAnnouncement) {
65
+ // CAS Announcement not available — emit a need
66
+ needs.push({
67
+ kind : 'NeedCASAnnouncement',
68
+ announcementHash,
69
+ beaconServiceId : this.service.id
70
+ });
71
+ continue;
72
+ }
73
+
74
+ // Look up this DID's update hash in the CAS Announcement
75
+ const updateHash = casAnnouncement[did];
76
+
77
+ // If no entry for this DID, this announcement doesn't contain an update for us — skip
78
+ if(!updateHash) {
79
+ continue;
80
+ }
81
+
82
+ // Look up the signed update in sidecar updateMap
83
+ const signedUpdate = sidecar.updateMap.get(updateHash);
84
+
85
+ if(!signedUpdate) {
86
+ // Signed update not available — emit a need
87
+ needs.push({
88
+ kind : 'NeedSignedUpdate',
89
+ updateHash,
90
+ beaconServiceId : this.service.id
91
+ });
92
+ continue;
93
+ }
94
+
95
+ updates.push([signedUpdate, signal.blockMetadata]);
96
+ }
97
+
98
+ return { updates, needs };
36
99
  }
37
100
 
38
101
  /**
39
- * Broadcast CAS Beacon signal to the Bitcoin network.
102
+ * Broadcasts a CAS Beacon signal to the Bitcoin network.
103
+ *
104
+ * Creates a CAS Announcement mapping the DID to the update hash, then broadcasts
105
+ * the hash of the announcement via OP_RETURN. The CAS Announcement is distributed
106
+ * to resolvers via sidecar data.
107
+ *
40
108
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
41
109
  * @param {KeyBytes} secretKey The secret key for signing the Bitcoin transaction.
42
110
  * @param {BitcoinConnection} bitcoin The Bitcoin network connection.
43
- * @return {Promise<SignedBTCR2Update>} The signed update that was broadcasted.
44
- * @throws {CASBeaconError} if broadcasting fails.
111
+ * @returns {Promise<SignedBTCR2Update>} The signed update that was broadcast.
112
+ * @throws {CASBeaconError} if the bitcoin address is invalid or unfunded.
45
113
  */
46
114
  async broadcastSignal(
47
115
  signedUpdate: SignedBTCR2Update,
48
116
  secretKey: KeyBytes,
49
117
  bitcoin: BitcoinConnection
50
118
  ): Promise<SignedBTCR2Update> {
51
- throw new CASBeaconError('Method not implemented.', `METHOD_NOT_IMPLEMENTED`, {signedUpdate, secretKey, bitcoin});
119
+ // Extract the DID from the beacon service id (strip the #fragment)
120
+ const did = this.service.id.split('#')[0];
121
+
122
+ // Hash the signed update (base64url for the CAS Announcement entry)
123
+ const updateHash = canonicalHash(signedUpdate);
124
+
125
+ // Create the CAS Announcement mapping this DID to its update hash
126
+ const casAnnouncement = { [did]: updateHash };
127
+
128
+ // TODO: Publish CAS Announcement to content-addressed store (e.g., IPFS via Helia)
129
+
130
+ // Canonicalize and hash the CAS Announcement for the OP_RETURN output
131
+ const announcementHash = hash(canonicalize(casAnnouncement));
132
+
133
+ // Convert the serviceEndpoint to a bitcoin address by removing the 'bitcoin:' prefix
134
+ const bitcoinAddress = this.service.serviceEndpoint.replace('bitcoin:', '');
135
+
136
+ // Query the Bitcoin network for UTXOs associated with the bitcoinAddress
137
+ const utxos = await bitcoin.rest.address.getUtxos(bitcoinAddress);
138
+
139
+ // If no utxos are found, throw an error indicating the address is unfunded.
140
+ if(!utxos.length) {
141
+ throw new CASBeaconError(
142
+ 'No UTXOs found, please fund address!',
143
+ 'UNFUNDED_BEACON_ADDRESS', { bitcoinAddress }
144
+ );
145
+ }
146
+
147
+ // Sort utxos by block height and take the most recent one
148
+ const utxo: AddressUtxo | undefined = utxos.sort(
149
+ (a, b) => b.status.block_height - a.status.block_height
150
+ ).shift();
151
+
152
+ // If no utxos are found, throw an error.
153
+ if(!utxo) {
154
+ throw new CASBeaconError(
155
+ 'Beacon bitcoin address unfunded or utxos unconfirmed.',
156
+ 'UNFUNDED_BEACON_ADDRESS', { bitcoinAddress }
157
+ );
158
+ }
159
+
160
+ // Get the previous tx to the utxo being spent
161
+ const prevTx = await bitcoin.rest.transaction.getHex(utxo.txid);
162
+
163
+ // Construct a spend transaction
164
+ const spendTx = new Psbt({ network: bitcoin.data })
165
+ // Spend tx contains the utxo as its input
166
+ .addInput({
167
+ hash : utxo.txid,
168
+ index : utxo.vout,
169
+ nonWitnessUtxo : Buffer.from(prevTx, 'hex')
170
+ })
171
+ // Add a change output minus a fee of 500 sats
172
+ // TODO: calculate fee based on transaction vsize and current fee rates
173
+ .addOutput({ address: bitcoinAddress, value: BigInt(utxo.value) - BigInt(500) })
174
+ // Add an OP_RETURN output containing the CAS Announcement hash
175
+ .addOutput({ script: script.compile([opcodes.OP_RETURN, announcementHash]), value: 0n });
176
+
177
+ // Construct a key pair and PSBT signer from the secret key
178
+ const keyPair = SchnorrKeyPair.fromSecret(secretKey);
179
+ const signer = {
180
+ publicKey : keyPair.publicKey.compressed,
181
+ sign : (hash: Uint8Array) => keyPair.secretKey.sign(hash, { scheme: 'ecdsa' }),
182
+ };
183
+
184
+ // Sign 0th input, finalize extract to hex in prep for broadcast
185
+ const signedTx = spendTx.signInput(0, signer)
186
+ .finalizeAllInputs()
187
+ .extractTransaction()
188
+ .toHex();
189
+
190
+ // Broadcast spendTx to the Bitcoin network.
191
+ const txid = await bitcoin.rest.transaction.send(signedTx);
192
+
193
+ // Log the txid of the broadcasted transaction
194
+ console.info(`CAS Beacon Signal Broadcasted with txid: ${txid}`);
195
+
196
+ // Return the signed update
197
+ return signedUpdate;
52
198
  }
53
199
  }
@@ -2,7 +2,7 @@ import { MethodError } from '@did-btcr2/common';
2
2
  import { Beacon } from './beacon.js';
3
3
  import { CASBeacon } from './cas-beacon.js';
4
4
  import { BeaconService } from './interfaces.js';
5
- import { SingletonBeacon } from './singleton.js';
5
+ import { SingletonBeacon } from './singleton-beacon.js';
6
6
  import { SMTBeacon } from './smt-beacon.js';
7
7
 
8
8
  /**
@@ -1,9 +1,9 @@
1
1
  import { AddressUtxo, BitcoinConnection } from '@did-btcr2/bitcoin';
2
- import { Canonicalization, INVALID_SIDECAR_DATA, KeyBytes, MISSING_UPDATE_DATA } from '@did-btcr2/common';
2
+ import { canonicalize, decode, encode, hash, KeyBytes } from '@did-btcr2/common';
3
3
  import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
4
4
  import { SchnorrKeyPair } from '@did-btcr2/keypair';
5
5
  import { opcodes, Psbt, script } from 'bitcoinjs-lib';
6
- import { base58btc } from 'multiformats/bases/base58';
6
+ import type { BeaconProcessResult, DataNeed } from '../resolver.js';
7
7
  import { SidecarData } from '../types.js';
8
8
  import { Beacon } from './beacon.js';
9
9
  import { SingletonBeaconError } from './error.js';
@@ -20,7 +20,6 @@ export class SingletonBeacon extends Beacon {
20
20
  /**
21
21
  * Creates an instance of SingletonBeacon.
22
22
  * @param {BeaconService} service The BeaconService object representing the funded beacon to announce the update to.
23
- *
24
23
  */
25
24
  constructor(service: BeaconService) {
26
25
  super({ ...service, type: 'SingletonBeacon' });
@@ -28,53 +27,38 @@ export class SingletonBeacon extends Beacon {
28
27
 
29
28
  /**
30
29
  * Processes an array of Beacon Signals associated with a Singleton Beacon Service.
31
- * @returns {Promise<SignedBTCR2Update | undefined>} The DID Update payload announced by the Beacon Signal.
32
- * @throws {SingletonBeaconError} if the signalTx is invalid or the signalSidecarData is invalid.
30
+ * @param {Array<BeaconSignal>} signals The beacon signals discovered on-chain.
31
+ * @param {SidecarData} sidecar The processed sidecar data.
32
+ * @returns {BeaconProcessResult} Successfully resolved updates and any data needs.
33
33
  */
34
- async processSignals(
34
+ processSignals(
35
35
  signals: Array<BeaconSignal>,
36
36
  sidecar: SidecarData
37
- ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>> {
38
- // Initialize an empty array to hold the BTCR2 signed updates
37
+ ): BeaconProcessResult {
39
38
  const updates = new Array<[SignedBTCR2Update, BlockMetadata]>();
39
+ const needs = new Array<DataNeed>();
40
40
 
41
- // Loop through each signal in signals
42
41
  for(const signal of signals) {
43
- // Grab the beacon signal bytes hash from the signal
44
- const updateHash = signal.signalBytes;
42
+ // Decode signal bytes from hex and re-encode to base64url for sidecar lookup
43
+ const updateHash = encode(decode(signal.signalBytes, 'hex'));
45
44
 
46
- // Use the updateHash as the sidecar data lookup key to retrieve the btcr2 update
45
+ // Look up the signed update in sidecar updateMap
47
46
  const signedUpdate = sidecar.updateMap.get(updateHash);
48
47
 
49
- // If no btcr2 update is found in sidecar data maps, throw missingUpdateData error.
50
48
  if(!signedUpdate) {
51
- throw new SingletonBeaconError(
52
- `BTCR2 Signed Update not found for update hash ${updateHash}.`,
53
- MISSING_UPDATE_DATA, signal
54
- );
49
+ // Data not available — emit a need instead of throwing
50
+ needs.push({
51
+ kind : 'NeedSignedUpdate',
52
+ updateHash,
53
+ beaconServiceId : this.service.id
54
+ });
55
+ continue;
55
56
  }
56
57
 
57
- // Canonicalize, hash and encode to base58btc the signed update object found in sidecar or CAS
58
- const encodedUpdate = Canonicalization.process(signedUpdate, { encoding: 'base58btc' });
59
-
60
- // Encode the signal bytes hex string to base58btc
61
- const signalBytes = base58btc.encode(Buffer.from(updateHash, 'hex'));
62
-
63
- // Check for mismatch between found sidecar/cas update hash and onchain beacon signal hash
64
- if (encodedUpdate !== signalBytes) {
65
- // If mismatch, throw invalidSidecarData error.
66
- throw new SingletonBeaconError(
67
- `Hash mismatch: sidecar update ${encodedUpdate} !== signal bytes ${signalBytes}.`,
68
- INVALID_SIDECAR_DATA, { encodedUpdate, signalBytes }
69
- );
70
- }
71
-
72
- // Push signedUpdate to updates array
73
58
  updates.push([signedUpdate, signal.blockMetadata]);
74
59
  }
75
60
 
76
- // Return the array of signed updates
77
- return updates;
61
+ return { updates, needs };
78
62
  }
79
63
  /**
80
64
  * Broadcasts a SingletonBeacon signal to the Bitcoin network.
@@ -120,7 +104,7 @@ export class SingletonBeacon extends Beacon {
120
104
  const prevTx = await bitcoin.rest.transaction.getHex(utxo.txid);
121
105
 
122
106
  // Canonicalize and hash the signed update for OP_RETURN output
123
- const updateHash = Canonicalization.andHash(signedUpdate);
107
+ const updateHash = hash(canonicalize(signedUpdate));
124
108
 
125
109
  // Construct a spend transaction
126
110
  const spendTx = new Psbt({ network: bitcoin.data })
@@ -1,10 +1,11 @@
1
1
  import { BitcoinConnection } from '@did-btcr2/bitcoin';
2
2
  import { KeyBytes } from '@did-btcr2/common';
3
3
  import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
4
+ import type { BeaconProcessResult } from '../resolver.js';
4
5
  import { SidecarData } from '../types.js';
5
6
  import { Beacon } from './beacon.js';
6
7
  import { SMTBeaconError } from './error.js';
7
- import { BeaconService, BeaconSignal, BlockMetadata } from './interfaces.js';
8
+ import { BeaconService, BeaconSignal } from './interfaces.js';
8
9
 
9
10
  /**
10
11
  * Implements {@link https://dcdpr.github.io/did-btcr2/terminology.html#smt-beacon | SMTBeacon}.
@@ -25,13 +26,13 @@ export class SMTBeacon extends Beacon {
25
26
  * Implements {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process-smt-beacon | 7.2.e.1 Process SMT Beacon}.
26
27
  * @param {Array<BeaconSignal>} signals The array of Beacon Signals to process.
27
28
  * @param {SidecarData} sidecar The sidecar data associated with the SMT Beacon.
28
- * @returns {Promise<Array<[SignedBTCR2Update, BlockMetadata]>>} The processed signals.
29
+ * @returns {BeaconProcessResult} The processed signals.
29
30
  * @throws {SMTBeaconError} if processing fails.
30
31
  */
31
32
  processSignals(
32
33
  signals: Array<BeaconSignal>,
33
34
  sidecar: SidecarData
34
- ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>> {
35
+ ): BeaconProcessResult {
35
36
  throw new SMTBeaconError('Method not implemented.', `METHOD_NOT_IMPLEMENTED`, {signals, sidecar});
36
37
  }
37
38
 
@@ -287,7 +287,7 @@ export class Identifier {
287
287
  network : 'regtest'
288
288
  }
289
289
  );
290
- return { keyPair: keyPair.toJSON(), did };
290
+ return { keyPair: keyPair.exportJSON(), did };
291
291
  }
292
292
 
293
293
  /**