@did-btcr2/method 0.19.0 → 0.22.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 (120) hide show
  1. package/README.md +223 -1
  2. package/dist/browser.js +3496 -4202
  3. package/dist/browser.mjs +3496 -4202
  4. package/dist/cjs/core/beacon/beacon.js +25 -0
  5. package/dist/cjs/core/beacon/beacon.js.map +1 -0
  6. package/dist/cjs/core/beacon/cas-beacon.js +20 -36
  7. package/dist/cjs/core/beacon/cas-beacon.js.map +1 -1
  8. package/dist/cjs/core/beacon/error.js +4 -4
  9. package/dist/cjs/core/beacon/error.js.map +1 -1
  10. package/dist/cjs/core/beacon/factory.js +5 -7
  11. package/dist/cjs/core/beacon/factory.js.map +1 -1
  12. package/dist/cjs/core/beacon/interfaces.js +1 -31
  13. package/dist/cjs/core/beacon/interfaces.js.map +1 -1
  14. package/dist/cjs/core/beacon/signal-discovery.js +183 -0
  15. package/dist/cjs/core/beacon/signal-discovery.js.map +1 -0
  16. package/dist/cjs/core/beacon/singleton.js +56 -86
  17. package/dist/cjs/core/beacon/singleton.js.map +1 -1
  18. package/dist/cjs/core/beacon/smt-beacon.js +22 -39
  19. package/dist/cjs/core/beacon/smt-beacon.js.map +1 -1
  20. package/dist/cjs/core/beacon/utils.js +4 -9
  21. package/dist/cjs/core/beacon/utils.js.map +1 -1
  22. package/dist/cjs/core/resolve.js +121 -307
  23. package/dist/cjs/core/resolve.js.map +1 -1
  24. package/dist/cjs/core/update.js +62 -154
  25. package/dist/cjs/core/update.js.map +1 -1
  26. package/dist/cjs/did-btcr2.js +100 -91
  27. package/dist/cjs/did-btcr2.js.map +1 -1
  28. package/dist/cjs/index.js +3 -1
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/utils/appendix.js +6 -15
  31. package/dist/cjs/utils/appendix.js.map +1 -1
  32. package/dist/cjs/utils/did-document-builder.js +5 -6
  33. package/dist/cjs/utils/did-document-builder.js.map +1 -1
  34. package/dist/cjs/utils/did-document.js +42 -38
  35. package/dist/cjs/utils/did-document.js.map +1 -1
  36. package/dist/esm/core/beacon/beacon.js +25 -0
  37. package/dist/esm/core/beacon/beacon.js.map +1 -0
  38. package/dist/esm/core/beacon/cas-beacon.js +20 -36
  39. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  40. package/dist/esm/core/beacon/error.js +4 -4
  41. package/dist/esm/core/beacon/error.js.map +1 -1
  42. package/dist/esm/core/beacon/factory.js +5 -7
  43. package/dist/esm/core/beacon/factory.js.map +1 -1
  44. package/dist/esm/core/beacon/interfaces.js +1 -31
  45. package/dist/esm/core/beacon/interfaces.js.map +1 -1
  46. package/dist/esm/core/beacon/signal-discovery.js +183 -0
  47. package/dist/esm/core/beacon/signal-discovery.js.map +1 -0
  48. package/dist/esm/core/beacon/singleton.js +56 -86
  49. package/dist/esm/core/beacon/singleton.js.map +1 -1
  50. package/dist/esm/core/beacon/smt-beacon.js +22 -39
  51. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  52. package/dist/esm/core/beacon/utils.js +4 -9
  53. package/dist/esm/core/beacon/utils.js.map +1 -1
  54. package/dist/esm/core/resolve.js +121 -307
  55. package/dist/esm/core/resolve.js.map +1 -1
  56. package/dist/esm/core/update.js +62 -154
  57. package/dist/esm/core/update.js.map +1 -1
  58. package/dist/esm/did-btcr2.js +100 -91
  59. package/dist/esm/did-btcr2.js.map +1 -1
  60. package/dist/esm/index.js +3 -1
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/utils/appendix.js +6 -15
  63. package/dist/esm/utils/appendix.js.map +1 -1
  64. package/dist/esm/utils/did-document-builder.js +5 -6
  65. package/dist/esm/utils/did-document-builder.js.map +1 -1
  66. package/dist/esm/utils/did-document.js +42 -38
  67. package/dist/esm/utils/did-document.js.map +1 -1
  68. package/dist/types/core/beacon/beacon.d.ts +44 -0
  69. package/dist/types/core/beacon/beacon.d.ts.map +1 -0
  70. package/dist/types/core/beacon/cas-beacon.d.ts +19 -30
  71. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  72. package/dist/types/core/beacon/error.d.ts +2 -2
  73. package/dist/types/core/beacon/error.d.ts.map +1 -1
  74. package/dist/types/core/beacon/factory.d.ts +4 -6
  75. package/dist/types/core/beacon/factory.d.ts.map +1 -1
  76. package/dist/types/core/beacon/interfaces.d.ts +7 -46
  77. package/dist/types/core/beacon/interfaces.d.ts.map +1 -1
  78. package/dist/types/core/beacon/signal-discovery.d.ts +25 -0
  79. package/dist/types/core/beacon/signal-discovery.d.ts.map +1 -0
  80. package/dist/types/core/beacon/singleton.d.ts +17 -30
  81. package/dist/types/core/beacon/singleton.d.ts.map +1 -1
  82. package/dist/types/core/beacon/smt-beacon.d.ts +21 -33
  83. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  84. package/dist/types/core/beacon/utils.d.ts.map +1 -1
  85. package/dist/types/core/interfaces.d.ts +1 -8
  86. package/dist/types/core/interfaces.d.ts.map +1 -1
  87. package/dist/types/core/resolve.d.ts +34 -47
  88. package/dist/types/core/resolve.d.ts.map +1 -1
  89. package/dist/types/core/types.d.ts +21 -8
  90. package/dist/types/core/types.d.ts.map +1 -1
  91. package/dist/types/core/update.d.ts +30 -73
  92. package/dist/types/core/update.d.ts.map +1 -1
  93. package/dist/types/did-btcr2.d.ts +44 -47
  94. package/dist/types/did-btcr2.d.ts.map +1 -1
  95. package/dist/types/index.d.ts +3 -1
  96. package/dist/types/index.d.ts.map +1 -1
  97. package/dist/types/utils/appendix.d.ts.map +1 -1
  98. package/dist/types/utils/did-document-builder.d.ts +5 -1
  99. package/dist/types/utils/did-document-builder.d.ts.map +1 -1
  100. package/dist/types/utils/did-document.d.ts +26 -21
  101. package/dist/types/utils/did-document.d.ts.map +1 -1
  102. package/package.json +8 -7
  103. package/src/core/beacon/beacon.ts +58 -0
  104. package/src/core/beacon/cas-beacon.ts +30 -44
  105. package/src/core/beacon/error.ts +5 -6
  106. package/src/core/beacon/factory.ts +7 -9
  107. package/src/core/beacon/interfaces.ts +7 -64
  108. package/src/core/beacon/signal-discovery.ts +237 -0
  109. package/src/core/beacon/singleton.ts +78 -100
  110. package/src/core/beacon/smt-beacon.ts +32 -49
  111. package/src/core/beacon/utils.ts +16 -13
  112. package/src/core/interfaces.ts +1 -9
  113. package/src/core/resolve.ts +163 -395
  114. package/src/core/types.ts +25 -8
  115. package/src/core/update.ts +91 -236
  116. package/src/did-btcr2.ts +154 -116
  117. package/src/index.ts +8 -1
  118. package/src/utils/appendix.ts +8 -22
  119. package/src/utils/did-document-builder.ts +5 -7
  120. package/src/utils/did-document.ts +80 -73
package/src/did-btcr2.ts CHANGED
@@ -1,16 +1,19 @@
1
1
  import { BitcoinNetworkConnection } from '@did-btcr2/bitcoin';
2
2
  import {
3
- Canonicalization,
4
3
  DocumentBytes,
4
+ HexString,
5
5
  IdentifierHrp,
6
6
  INVALID_DID_DOCUMENT,
7
+ INVALID_DID_UPDATE,
7
8
  KeyBytes,
8
9
  METHOD_NOT_SUPPORTED,
9
10
  MethodError,
10
11
  MISSING_UPDATE_DATA,
11
12
  PatchOperation,
12
- ResolveError
13
+ ResolveError,
14
+ UpdateError
13
15
  } from '@did-btcr2/common';
16
+ import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
14
17
  import {
15
18
  Did,
16
19
  DidError,
@@ -21,17 +24,14 @@ import {
21
24
  } from '@web5/dids';
22
25
  import { initEccLib } from 'bitcoinjs-lib';
23
26
  import * as tinysecp from 'tiny-secp256k1';
27
+ import { BeaconService } from './core/beacon/interfaces.js';
24
28
  import { BeaconUtils } from './core/beacon/utils.js';
25
29
  import { Identifier } from './core/identifier.js';
26
30
  import { ResolutionOptions } from './core/interfaces.js';
27
31
  import { Resolve } from './core/resolve.js';
28
- import { SidecarData } from './core/types.js';
29
32
  import { Update } from './core/update.js';
30
33
  import { Appendix } from './utils/appendix.js';
31
- import { DidDocument, DidVerificationMethod } from './utils/did-document.js';
32
-
33
- // TODO: convert to API driver
34
- export const canonicalization = new Canonicalization();
34
+ import { Btcr2DidDocument, DidVerificationMethod } from './utils/did-document.js';
35
35
 
36
36
  export type Btcr2Identifier = string;
37
37
 
@@ -44,7 +44,7 @@ export interface DidCreateOptions {
44
44
  network?: string;
45
45
  }
46
46
 
47
- // TODO: convert to API driver
47
+ // TODO: convert to API driver?
48
48
  /** Initialize tiny secp256k1 */
49
49
  initEccLib(tinysecp);
50
50
 
@@ -62,7 +62,9 @@ initEccLib(tinysecp);
62
62
  * @implements {DidMethod}
63
63
  */
64
64
  export class DidBtcr2 implements DidMethod {
65
- /** @type {string} Name of the DID method, as defined in the DID BTCR2 specification */
65
+ /**
66
+ * Name of the DID method, as defined in the DID BTCR2 specification
67
+ */
66
68
  static methodName: string = 'btcr2';
67
69
 
68
70
  /**
@@ -75,11 +77,16 @@ export class DidBtcr2 implements DidMethod {
75
77
  * @param {string} options.network The Bitcoin network to use for the identifier, e.g. 'bitcoin', 'testnet', etc. Defaults to 'bitcoin'.
76
78
  * @returns {Promise<Btcr2Identifier>} Promise resolving to a Btcr2Identifier string.
77
79
  * @throws {MethodError} if any of the checks fail
80
+ * @example
81
+ * ```ts
82
+ * const genesisBytes = SchnorrKeyPair.generate().publicKey.compressed;
83
+ * const did = DidBtcr2.create(genesisBytes, { idType: 'KEY', network: 'regtest' });
84
+ * ```
78
85
  */
79
- static async create(
86
+ static create(
80
87
  genesisBytes: KeyBytes | DocumentBytes,
81
88
  options?: DidCreateOptions
82
- ): Promise<Btcr2Identifier> {
89
+ ): Btcr2Identifier {
83
90
  // Deconstruct the idType, version and network from the options, setting defaults if not given
84
91
  const { idType, version = 1, network = 'bitcoin' } = options || {};
85
92
 
@@ -95,7 +102,7 @@ export class DidBtcr2 implements DidMethod {
95
102
  }
96
103
 
97
104
  /**
98
- * Entry point for section {@link https://dcdpr.github.io/did-btcr2/#read | 7.2 Resolve}.
105
+ * Entry point for section {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html | 7.2 Resolve}.
99
106
  * See specification for the {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process | Resolve Process}.
100
107
  * See {@link Resolve | Resolve (class)} for class implementation.
101
108
  *
@@ -104,32 +111,33 @@ export class DidBtcr2 implements DidMethod {
104
111
  * blockchain by Authorized Beacon Signals. The Initial DID Document is either
105
112
  * deterministically created from the DID or provided by Sidecar Data.
106
113
  *
107
- * @param {string} did a valid did:btcr2 identifier to be resolved
108
- * @param {ResolutionOptions} resolutionOptions see {@link https://www.w3.org/TR/did-1.0/#did-resolution-options | ResolutionOptions}
109
- * @param {number} resolutionOptions.versionId optional version of the identifier and/or DID document
110
- * @param {number} resolutionOptions.versionTime optional timestamp used during resolution as a bound for when to stop resolving
111
- * @param {DidDocument} resolutionOptions.sidecar optional data necessary for resolving a DID
114
+ * @param {string} did The did:btcr2 identifier to be resolved.
115
+ * @param {ResolutionOptions} resolutionOptions Options used during the resolution process.
112
116
  * @returns {Promise<DidResolutionResult>} Promise resolving to a DID Resolution Result containing the `targetDocument`
113
- * @throws {Error} if the resolution fails for any reason
114
- * @throws {DidError} InvalidDid if the identifier is invalid
117
+ * @throws {ResolveError} If the resolution process fails at any step.
115
118
  * @example
116
119
  * ```ts
117
120
  * const resolution = await DidBtcr2.resolve(
118
- * 'did:btcr2:k1q0dygyp3gz969tp46dychzy4q78c2k3js68kvyr0shanzg67jnuez2cfplh'
121
+ * 'did:btcr2:k1qgpr45cheptyjekl3cex80xfnkwhxnlclecwwf92gvdjrszm2uwhzlcxu5xte'
119
122
  * )
120
123
  * ```
121
124
  */
122
- static async resolve(did: string, resolutionOptions: ResolutionOptions = {drivers: {}}): Promise<DidResolutionResult> {
125
+ static async resolve(
126
+ did: string,
127
+ resolutionOptions: ResolutionOptions = {}
128
+ ): Promise<DidResolutionResult> {
123
129
  try {
130
+ // Set versionId from resolutionOptions
131
+ const versionId = resolutionOptions.versionId;
124
132
 
125
133
  // Initialize an empty DID Resolution Result
126
134
  const didResolutionResult: DidResolutionResult = {
127
135
  '@context' : 'https://w3id.org/did-resolution/v1',
128
136
  didResolutionMetadata : { contentType: 'application/ld+json' },
129
137
  didDocumentMetadata : {
138
+ versionId,
130
139
  deactivated : false,
131
140
  updated : undefined,
132
- versionId : resolutionOptions.versionId,
133
141
  confirmations : undefined,
134
142
  },
135
143
  didDocument : null,
@@ -139,68 +147,72 @@ export class DidBtcr2 implements DidMethod {
139
147
  const didComponents = Identifier.decode(did);
140
148
 
141
149
  // Process sidecar if provided
142
- const sidecarData = Resolve.processSidecarData(resolutionOptions.sidecar);
143
-
144
- // Establish a connection to a bitcoin network
145
- if(!resolutionOptions.drivers.bitcoin) {
146
- resolutionOptions.drivers.bitcoin = new BitcoinNetworkConnection();
147
- // Set the network based on the decoded identifier
148
- resolutionOptions.drivers.bitcoin.setActiveNetwork(didComponents.network);
149
- }
150
+ const sidecarData = Resolve.sidecarData(resolutionOptions.sidecar);
150
151
 
151
152
  // Parse the genesis document from the resolution options if provided
152
153
  const genesisDocument = resolutionOptions.sidecar?.genesisDocument;
154
+
153
155
  // Since genesisDocument is optional, check if it exists
154
156
  if(!genesisDocument) {
155
157
  // If no genesisDocument and x HRP, throw MISSING_UPDATE_DATA error
156
158
  if(didComponents.hrp === IdentifierHrp.x)
157
159
  throw new ResolveError(
158
160
  'External resolution requires genesisDocument',
159
- MISSING_UPDATE_DATA, { resolutionOptions }
161
+ MISSING_UPDATE_DATA, resolutionOptions
160
162
  );
161
163
  }
162
164
 
163
165
  // Establish the current document
164
- const currentDocument = await Resolve.establishCurrentDocument(didComponents, genesisDocument);
166
+ const currentDocument = await Resolve.currentDocument(didComponents, genesisDocument);
165
167
 
166
168
  // Extract all Beacon services from the current DID Document
167
169
  const beaconServices = currentDocument.service
168
170
  .filter(BeaconUtils.isBeaconService)
169
171
  .map(BeaconUtils.parseBeaconServiceEndpoint);
170
172
 
173
+ // Check if bitcoin driver provided
174
+ if(!resolutionOptions?.drivers?.bitcoin) {
175
+ // If not, initialize default drivers
176
+ resolutionOptions.drivers = resolutionOptions.drivers || {};
177
+ // Set bitcoin driver to default BitcoinNetworkConnection
178
+ resolutionOptions.drivers.bitcoin = new BitcoinNetworkConnection();
179
+ // Set the network based on the decoded identifier
180
+ resolutionOptions.drivers.bitcoin.setActiveNetwork(didComponents.network);
181
+ }
182
+
183
+ // Get the bitcoin driver from the resolution options
184
+ const bitcoin = resolutionOptions.drivers.bitcoin;
185
+
171
186
  // Process the Beacon Signals to get the required updates
172
- const unsortedUpdates = await Resolve.processBeaconSignals(
187
+ const unsortedUpdates = await Resolve.beaconSignals(
173
188
  beaconServices,
174
189
  sidecarData,
175
- resolutionOptions.drivers.bitcoin,
176
- resolutionOptions.fullBlockchainTraversal
190
+ bitcoin
177
191
  );
178
192
 
179
193
  // If no updates found, return the current document
180
194
  if(!unsortedUpdates.length) {
181
- // Set the current document in the didResolutionResult
195
+ // Set the didDocument in didResolutionResult based on currentDocument
182
196
  didResolutionResult.didDocument = currentDocument;
183
-
184
- // Set the deactivated status in the didDocumentMetadata
197
+ // Set other required fields in the didResolutionResult
185
198
  didResolutionResult.didDocumentMetadata.deactivated = !!currentDocument.deactivated;
199
+ didResolutionResult.didDocumentMetadata.versionId = versionId ?? '1';
186
200
 
187
201
  // Return the didResolutionResult early
188
202
  return didResolutionResult;
189
203
  }
190
204
 
191
205
  // Process the updates to apply updates to bring the current DID Document to its more current state
192
- const result = await Resolve.processUpdatesArray(
206
+ const result = await Resolve.updates(
193
207
  currentDocument,
194
208
  unsortedUpdates,
195
209
  resolutionOptions.versionTime,
196
- resolutionOptions.versionId
210
+ versionId
197
211
  );
198
212
 
199
213
  // Set all of the required fields in the didResolutionResult
200
- didResolutionResult.didDocument = result.currentDocument;
201
- didResolutionResult.didDocumentMetadata.confirmations = result.confirmations;
202
- didResolutionResult.didDocumentMetadata.versionId = result.versionId;
203
- didResolutionResult.didDocumentMetadata.deactivated = !!result.currentDocument.deactivated;
214
+ didResolutionResult.didDocument = result.didDocument;
215
+ didResolutionResult.didDocumentMetadata = result.metadata;
204
216
 
205
217
  // Return didResolutionResult;
206
218
  return didResolutionResult;
@@ -221,92 +233,118 @@ export class DidBtcr2 implements DidMethod {
221
233
  }
222
234
 
223
235
  /**
224
- * Entry point for section {@link https://dcdpr.github.io/did-btcr2/#update | 4.3 Update}.
225
- * See {@link Update} for implementation details.
226
- *
227
- * An update to a did:btcr2 document is an invoked capability using the ZCAP-LD data format, signed by a
228
- * verificationMethod that has the authority to make the update as specified in the previous DID document. Capability
229
- * invocations for updates MUST be authorized using Data Integrity following the bip340-jcs-2025
230
- * cryptosuite with a proofPurpose of capabilityInvocation.
231
- *
232
- * The Update algorithm takes as inputs a Identifier, sourceDocument, sourceVersionId, documentPatch, a
233
- * verificationMethodId and an array of beaconIds. The sourceDocument is the DID document being updated. The
234
- * documentPatch is a JSON Patch object containing a set of transformations to be applied to the sourceDocument.
235
- * The result of these transformations MUST produce a DID document conformant to the DID Core specification. The
236
- * verificationMethodId is an identifier for a verificationMethod within the sourceDocument. The verificationMethod
237
- * identified MUST be a BIP340 Multikey. The beaconIds MUST identify service endpoints with one of the three Beacon
238
- * Types SingletonBeacon, CASBeacon, and SMTBeacon.
236
+ * Entry point for section {@link https://dcdpr.github.io/did-btcr2/#read | 7.3 Update}.
237
+ * See specification for the {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process | Resolve Process}.
238
+ * See {@link Update | Update (class)} for class implementation.
239
239
  *
240
- * @param {UpdateParams} params Required parameters for the update operation.
241
- * @param {string} params.identifier The btcr2 identifier to be updated.
242
- * @param {DidDocument} params.sourceDocument The DID document being updated.
243
- * @param {string} params.sourceVersionId The versionId of the source document.
244
- * @param {PatchOperation} params.documentPatch The JSON patch to be applied to the source document.
245
- * @param {string} params.verificationMethodId The verificationMethod ID to sign the update
246
- * @param {string[]} params.beaconIds The beacon IDs to announce the update
247
- * @returns {Promise<void>} Promise resolving to void
248
- * @throws {MethodError} if the verificationMethod type is not `Multikey` or the publicKeyMultibase header is not `zQ3s`
240
+ * BTCR2 DID documents can be updated by anchoring BTCR2 Updates to Bitcoin transactions. These transactions MAY be
241
+ * published to the Bitcoin network. Any property in the DID document may be updated except the id. Doing so would
242
+ * invalidate the DID document.
243
+ * @param params An object containing the parameters for the update operation.
244
+ * @param {Btcr2DidDocument} params.sourceDocument The DID document being updated.
245
+ * @param {PatchOperation[]} params.patches The array of JSON Patch operations to apply to the sourceDocument.
246
+ * @param {string} params.sourceVersionId The version ID before applying the update.
247
+ * @param {string} params.verificationMethodId The verificationMethod ID to sign the update with.
248
+ * @param {string} params.beaconId The beacon ID associated with the update.
249
+ * @param {KeyBytes | HexString} [params.signingMaterial] Optional signing material (key bytes or hex string).
250
+ * @param {BitcoinNetworkConnection} [params.bitcoin] Optional Bitcoin network connection for announcing the update. If not provided, a default connection will be initialized.
251
+ * @return {Promise<SignedBTCR2Update>} Promise resolving to the signed BTCR2 update.
252
+ * @throws {UpdateError} if no verificationMethod, verificationMethod type is not `Multikey` or the publicKeyMultibase
253
+ * header is not `zQ3s`
249
254
  */
250
- public static async update(params: {
251
- identifier: string;
252
- sourceDocument: DidDocument;
255
+ static async update({
256
+ sourceDocument,
257
+ patches,
258
+ sourceVersionId,
259
+ verificationMethodId,
260
+ beaconId,
261
+ signingMaterial,
262
+ bitcoin,
263
+ }: {
264
+ sourceDocument: Btcr2DidDocument;
265
+ patches: PatchOperation[];
253
266
  sourceVersionId: number;
254
- patch: PatchOperation[];
255
267
  verificationMethodId: string;
256
- beaconIds: string[];
257
- }): Promise<SidecarData> {
258
- // Deconstruct the params
259
- const {
260
- identifier,
261
- sourceDocument,
262
- sourceVersionId,
263
- patch,
264
- verificationMethodId: methodId,
265
- beaconIds,
266
- } = params;
267
-
268
- // 1. Set unsignedUpdate to the result of passing Identifier, sourceDocument,
269
- // sourceVersionId, and documentPatch into the Construct DID Update
270
- // Payload algorithm.
271
- const unsignedUpdate = await Update.construct({
272
- identifier,
273
- sourceDocument,
274
- sourceVersionId,
275
- patch,
276
- });
277
-
278
- // 2. Set verificationMethod to the result of retrieving the verificationMethod
279
- // from sourceDocument using the verificationMethodId.
280
- const verificationMethod = this.getSigningMethod(sourceDocument, methodId);
268
+ beaconId: string;
269
+ signingMaterial?: KeyBytes | HexString;
270
+ bitcoin?: BitcoinNetworkConnection;
271
+ }): Promise<SignedBTCR2Update> {
272
+ // TODO: provide KMS as alternative
273
+ // If no signingMaterial provided, throw an UpdateError with INVALID_DID_UPDATE.
274
+ if (!signingMaterial) {
275
+ throw new UpdateError(
276
+ 'Missing signing material for update',
277
+ INVALID_DID_UPDATE, {signingMaterial}
278
+ );
279
+ }
280
+
281
+ // Convert signingMaterial to bytes if it's a hex string
282
+ const secretKey = typeof signingMaterial === 'string'
283
+ ? Buffer.from(signingMaterial, 'hex')
284
+ : signingMaterial;
285
+
286
+ // Validate that the verificationMethodId is authorized for capabilityInvocation
287
+ if(!sourceDocument.capabilityInvocation?.some(vr => vr === verificationMethodId)) {
288
+ throw new UpdateError(
289
+ 'Invalid verificationMethodId: not authorized for capabilityInvocation',
290
+ INVALID_DID_DOCUMENT, sourceDocument
291
+ );
292
+ }
293
+
294
+ // Get the verification method to be used for signing the update
295
+ const verificationMethod = this.getSigningMethod(sourceDocument, verificationMethodId);
281
296
 
282
297
  // Validate the verificationMethod exists in the sourceDocument
283
298
  if (!verificationMethod) {
284
- throw new MethodError('Verification method not found in did document', INVALID_DID_DOCUMENT, sourceDocument);
299
+ throw new UpdateError(
300
+ 'Invalid verificationMethod: not found in source document',
301
+ INVALID_DID_DOCUMENT, {sourceDocument, verificationMethodId}
302
+ );
285
303
  }
286
304
 
287
- // 3. Validate the verificationMethod is a BIP340 Multikey:
288
- // 3.1 verificationMethod.type == Multikey
305
+ // Validate the verificationMethod is of type 'Multikey'
289
306
  if (verificationMethod.type !== 'Multikey') {
290
- throw new MethodError('Invalid type: must be type "Multikey"', INVALID_DID_DOCUMENT, verificationMethod);
307
+ throw new UpdateError(
308
+ 'Invalid verificationMethod: verificationMethod.type must be "Multikey"',
309
+ INVALID_DID_DOCUMENT, verificationMethod
310
+ );
291
311
  }
292
312
 
293
- // 3.2 verificationMethod.publicKeyMultibase[4] == zQ3s
294
- const mbasePrefix = verificationMethod.publicKeyMultibase?.slice(0, 4);
295
- if (mbasePrefix !== 'zQ3s') {
296
- throw new MethodError(`Invalid publicKeyMultibase prefix ${mbasePrefix}`, INVALID_DID_DOCUMENT, verificationMethod);
313
+ // Validate the publicKeyMultibase prefix is 'zQ3s'
314
+ if (verificationMethod.publicKeyMultibase?.slice(0, 4) !== 'zQ3s') {
315
+ throw new UpdateError(
316
+ 'Invalid verificationMethodId: publicKeyMultibase prefix must start with "zQ3s"',
317
+ INVALID_DID_DOCUMENT, verificationMethod
318
+ );
297
319
  }
298
320
 
299
- // 4. Set didUpdateInvocation to the result of passing Identifier, unsignedUpdate as didUpdatePayload, and
300
- // verificationMethod to the Invoke DID Update Payload algorithm.
301
- const signedUpdate = await Update.invoke({ identifier, verificationMethod, unsignedUpdate });
321
+ // Construct an unsigned update following the BTCR2 Update construction algorithm
322
+ const update = await Update.construct(sourceDocument, patches, sourceVersionId);
323
+
324
+ // Sign the unsigned update using the specified verification method
325
+ const signed = await Update.sign(sourceDocument.id, update, verificationMethod, secretKey);
326
+
327
+ // Filter sourceDocument services to get beaconServices matching beaconIds
328
+ const beaconService = sourceDocument.service
329
+ .filter((service: BeaconService) => service.id === beaconId)
330
+ .filter((service: BeaconService): service is BeaconService => !!service)
331
+ .shift();
332
+
333
+ // If no matching beacon service found, throw an UpdateError with INVALID_DID_UPDATE.
334
+ if(!beaconService) {
335
+ throw new UpdateError(
336
+ 'No beacon service found for provided beaconId',
337
+ INVALID_DID_UPDATE, {sourceDocument, beaconId}
338
+ );
339
+ }
340
+ // If no bitcoin network connection provided, initialize default
341
+ bitcoin ??= new BitcoinNetworkConnection();
302
342
 
303
- // 5. Set signalsMetadata to the result of passing Identifier, sourceDocument, beaconIds and didUpdateInvocation
304
- // to the Announce DID Update algorithm.
305
- const signalsMetadata = await Update.announce({ sourceDocument, beaconIds, signedUpdate });
343
+ // Announce the signed update to the blockchain using the specified beacon(s)
344
+ await Update.announce(beaconService, signed, secretKey, bitcoin);
306
345
 
307
- // 6. Return signalsMetadata. It is up to implementations to ensure that the signalsMetadata is persisted.
308
- return signalsMetadata;
309
- // TODO: Should we be applying the patch, producing a target did document and returning it?
346
+ // Return signed update if announced successfully
347
+ return signed;
310
348
  }
311
349
 
312
350
  /**
@@ -314,12 +352,12 @@ export class DidBtcr2 implements DidMethod {
314
352
  * for signing messages and credentials. If given, the `methodId` parameter is used to select the
315
353
  * verification method. If not given, the Identity Key's verification method with an ID fragment
316
354
  * of '#initialKey' is used.
317
- * @param {DidDocument} didDocument The DID Document of the `did:btcr2` identifier.
355
+ * @param {Btcr2DidDocument} didDocument The DID Document of the `did:btcr2` identifier.
318
356
  * @param {string} [methodId] Optional verification method ID to be used for signing.
319
357
  * @returns {DidVerificationMethod} Promise resolving to the {@link DidVerificationMethod} object used for signing.
320
358
  * @throws {DidError} if the parsed did method does not match `btcr2` or signing method could not be determined.
321
359
  */
322
- public static getSigningMethod(didDocument: DidDocument, methodId?: string): DidVerificationMethod {
360
+ static getSigningMethod(didDocument: Btcr2DidDocument, methodId?: string): DidVerificationMethod {
323
361
  // Set the default methodId to the first assertionMethod if not given
324
362
  methodId ??= '#initialKey';
325
363
 
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './core/beacon/aggregation/cohort/index.js';
2
+ export * from './core/beacon/aggregation/cohort/status.js';
3
+
2
4
  export * from './core/beacon/aggregation/cohort/messages/base.js';
3
5
  export * from './core/beacon/aggregation/cohort/messages/constants.js';
4
6
  export * from './core/beacon/aggregation/cohort/messages/index.js';
@@ -12,20 +14,25 @@ export * from './core/beacon/aggregation/cohort/messages/sign/authorization-requ
12
14
  export * from './core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js';
13
15
  export * from './core/beacon/aggregation/cohort/messages/sign/request-signature.js';
14
16
  export * from './core/beacon/aggregation/cohort/messages/sign/signature-authorization.js';
15
- export * from './core/beacon/aggregation/cohort/status.js';
17
+
16
18
  export * from './core/beacon/aggregation/communication/adapter/did-comm.js';
17
19
  export * from './core/beacon/aggregation/communication/adapter/nostr.js';
20
+
18
21
  export * from './core/beacon/aggregation/communication/error.js';
19
22
  export * from './core/beacon/aggregation/communication/factory.js';
20
23
  export * from './core/beacon/aggregation/communication/service.js';
24
+
21
25
  export * from './core/beacon/aggregation/coordinator.js';
22
26
  export * from './core/beacon/aggregation/participant.js';
23
27
  export * from './core/beacon/aggregation/session/index.js';
24
28
  export * from './core/beacon/aggregation/session/status.js';
29
+
30
+ export * from './core/beacon/beacon.js';
25
31
  export * from './core/beacon/cas-beacon.js';
26
32
  export * from './core/beacon/error.js';
27
33
  export * from './core/beacon/factory.js';
28
34
  export * from './core/beacon/interfaces.js';
35
+ export * from './core/beacon/signal-discovery.js';
29
36
  export * from './core/beacon/singleton.js';
30
37
  export * from './core/beacon/smt-beacon.js';
31
38
  export * from './core/beacon/utils.js';
@@ -1,4 +1,4 @@
1
- import { HashBytes, W3C_ZCAP_V1 } from '@did-btcr2/common';
1
+ import { HashBytes } from '@did-btcr2/common';
2
2
  import { strings } from '@helia/strings';
3
3
  import {
4
4
  DidDocument,
@@ -109,27 +109,13 @@ export class Appendix {
109
109
  * }
110
110
  * ```
111
111
  */
112
- public static deriveRootCapability(identifier: string): RootCapability {
113
- // 1. Define rootCapability as an empty object.
114
- const rootCapability = {} as RootCapability;
115
-
116
- // 2. Set rootCapability.@context to ‘https://w3id.org/zcap/v1’.
117
- rootCapability['@context'] = W3C_ZCAP_V1;
118
-
119
- // 3. Set encodedIdentifier to result of calling algorithm encodeURIComponent(identifier).
120
- const encodedIdentifier = encodeURIComponent(identifier);
121
-
122
- // 4. Set rootCapability.id to urn:zcap:root:${encodedIdentifier}.
123
- rootCapability.id = `urn:zcap:root:${encodedIdentifier}`;
124
-
125
- // 5. Set rootCapability.controller to identifier.
126
- rootCapability.controller = identifier;
127
-
128
- // 6. Set rootCapability.invocationTarget to identifier.
129
- rootCapability.invocationTarget = identifier;
130
-
131
- // 7. Return rootCapability.
132
- return rootCapability;
112
+ static deriveRootCapability(identifier: string): RootCapability {
113
+ return {
114
+ '@context' : 'https://w3id.org/zcap/v1',
115
+ id : `urn:zcap:root:${encodeURIComponent(identifier)}`,
116
+ controller : identifier,
117
+ invocationTarget : identifier,
118
+ };
133
119
  }
134
120
 
135
121
 
@@ -2,6 +2,11 @@ import { DidDocumentError, INVALID_DID_DOCUMENT } from '@did-btcr2/common';
2
2
  import { BeaconService } from '../core/beacon/interfaces.js';
3
3
  import { DidDocument, DidVerificationMethod } from './did-document.js';
4
4
 
5
+ /**
6
+ * A builder class for constructing DID Documents.
7
+ * @type {DidDocumentBuilder}
8
+ * @class DidDocumentBuilder
9
+ */
5
10
  export class DidDocumentBuilder {
6
11
  private document: Partial<DidDocument> = {};
7
12
 
@@ -17,13 +22,6 @@ export class DidDocumentBuilder {
17
22
  }
18
23
  }
19
24
 
20
- withController(controller?: Array<string>): this {
21
- if (controller) {
22
- this.document.controller = controller ?? [this.document.id!];
23
- }
24
- return this;
25
- }
26
-
27
25
  withAuthentication(authentication: Array<string | DidVerificationMethod>): this {
28
26
  if (authentication) {
29
27
  this.document.authentication = authentication;