@did-btcr2/method 0.24.1 → 0.25.2

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 (101) hide show
  1. package/dist/browser.js +1541 -26561
  2. package/dist/browser.mjs +1541 -26561
  3. package/dist/cjs/core/beacon/aggregation/cohort/index.js +2 -1
  4. package/dist/cjs/core/beacon/aggregation/cohort/index.js.map +1 -1
  5. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js +3 -2
  6. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  7. package/dist/cjs/core/beacon/aggregation/coordinator.js +2 -1
  8. package/dist/cjs/core/beacon/aggregation/coordinator.js.map +1 -1
  9. package/dist/cjs/core/beacon/aggregation/participant.js +3 -2
  10. package/dist/cjs/core/beacon/aggregation/participant.js.map +1 -1
  11. package/dist/cjs/core/beacon/beacon.js.map +1 -1
  12. package/dist/cjs/core/beacon/cas-beacon.js +120 -7
  13. package/dist/cjs/core/beacon/cas-beacon.js.map +1 -1
  14. package/dist/cjs/core/beacon/factory.js +1 -1
  15. package/dist/cjs/core/beacon/factory.js.map +1 -1
  16. package/dist/cjs/core/beacon/signal-discovery.js +1 -1
  17. package/dist/cjs/core/beacon/signal-discovery.js.map +1 -1
  18. package/dist/cjs/core/beacon/{singleton.js → singleton-beacon.js} +20 -27
  19. package/dist/cjs/core/beacon/singleton-beacon.js.map +1 -0
  20. package/dist/cjs/core/beacon/smt-beacon.js +1 -1
  21. package/dist/cjs/core/beacon/smt-beacon.js.map +1 -1
  22. package/dist/{esm/core/resolve.js → cjs/core/resolver.js} +241 -93
  23. package/dist/cjs/core/resolver.js.map +1 -0
  24. package/dist/cjs/core/update.js +5 -5
  25. package/dist/cjs/core/update.js.map +1 -1
  26. package/dist/cjs/did-btcr2.js +39 -96
  27. package/dist/cjs/did-btcr2.js.map +1 -1
  28. package/dist/cjs/index.js +2 -2
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/esm/core/beacon/aggregation/cohort/index.js +2 -1
  31. package/dist/esm/core/beacon/aggregation/cohort/index.js.map +1 -1
  32. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +3 -2
  33. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  34. package/dist/esm/core/beacon/aggregation/coordinator.js +2 -1
  35. package/dist/esm/core/beacon/aggregation/coordinator.js.map +1 -1
  36. package/dist/esm/core/beacon/aggregation/participant.js +3 -2
  37. package/dist/esm/core/beacon/aggregation/participant.js.map +1 -1
  38. package/dist/esm/core/beacon/beacon.js.map +1 -1
  39. package/dist/esm/core/beacon/cas-beacon.js +120 -7
  40. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  41. package/dist/esm/core/beacon/factory.js +1 -1
  42. package/dist/esm/core/beacon/factory.js.map +1 -1
  43. package/dist/esm/core/beacon/signal-discovery.js +1 -1
  44. package/dist/esm/core/beacon/signal-discovery.js.map +1 -1
  45. package/dist/esm/core/beacon/{singleton.js → singleton-beacon.js} +20 -27
  46. package/dist/esm/core/beacon/singleton-beacon.js.map +1 -0
  47. package/dist/esm/core/beacon/smt-beacon.js +1 -1
  48. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  49. package/dist/{cjs/core/resolve.js → esm/core/resolver.js} +241 -93
  50. package/dist/esm/core/resolver.js.map +1 -0
  51. package/dist/esm/core/update.js +5 -5
  52. package/dist/esm/core/update.js.map +1 -1
  53. package/dist/esm/did-btcr2.js +39 -96
  54. package/dist/esm/did-btcr2.js.map +1 -1
  55. package/dist/esm/index.js +2 -2
  56. package/dist/esm/index.js.map +1 -1
  57. package/dist/types/core/beacon/aggregation/cohort/index.d.ts.map +1 -1
  58. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +1 -1
  59. package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +1 -1
  60. package/dist/types/core/beacon/aggregation/participant.d.ts.map +1 -1
  61. package/dist/types/core/beacon/beacon.d.ts +9 -4
  62. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  63. package/dist/types/core/beacon/cas-beacon.d.ts +26 -7
  64. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  65. package/dist/types/core/beacon/{singleton.d.ts → singleton-beacon.d.ts} +7 -5
  66. package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -0
  67. package/dist/types/core/beacon/smt-beacon.d.ts +4 -3
  68. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  69. package/dist/types/core/interfaces.d.ts +5 -15
  70. package/dist/types/core/interfaces.d.ts.map +1 -1
  71. package/dist/types/core/resolver.d.ts +167 -0
  72. package/dist/types/core/resolver.d.ts.map +1 -0
  73. package/dist/types/core/update.d.ts +3 -3
  74. package/dist/types/core/update.d.ts.map +1 -1
  75. package/dist/types/did-btcr2.d.ts +16 -16
  76. package/dist/types/did-btcr2.d.ts.map +1 -1
  77. package/dist/types/index.d.ts +2 -2
  78. package/dist/types/index.d.ts.map +1 -1
  79. package/package.json +5 -6
  80. package/src/core/beacon/aggregation/cohort/index.ts +2 -1
  81. package/src/core/beacon/aggregation/communication/adapter/nostr.ts +3 -2
  82. package/src/core/beacon/aggregation/coordinator.ts +2 -1
  83. package/src/core/beacon/aggregation/participant.ts +3 -2
  84. package/src/core/beacon/beacon.ts +9 -5
  85. package/src/core/beacon/cas-beacon.ts +157 -10
  86. package/src/core/beacon/factory.ts +1 -1
  87. package/src/core/beacon/signal-discovery.ts +1 -1
  88. package/src/core/beacon/{singleton.ts → singleton-beacon.ts} +21 -36
  89. package/src/core/beacon/smt-beacon.ts +4 -3
  90. package/src/core/interfaces.ts +5 -16
  91. package/src/core/{resolve.ts → resolver.ts} +355 -130
  92. package/src/core/update.ts +7 -7
  93. package/src/did-btcr2.ts +42 -132
  94. package/src/index.ts +2 -2
  95. package/dist/cjs/core/beacon/singleton.js.map +0 -1
  96. package/dist/cjs/core/resolve.js.map +0 -1
  97. package/dist/esm/core/beacon/singleton.js.map +0 -1
  98. package/dist/esm/core/resolve.js.map +0 -1
  99. package/dist/types/core/beacon/singleton.d.ts.map +0 -1
  100. package/dist/types/core/resolve.d.ts +0 -93
  101. package/dist/types/core/resolve.d.ts.map +0 -1
@@ -0,0 +1,167 @@
1
+ import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
2
+ import { DidDocument } from '../utils/did-document.js';
3
+ import { BeaconService, BeaconSignal, BlockMetadata } from './beacon/interfaces.js';
4
+ import { DidComponents } from './identifier.js';
5
+ import { CASAnnouncement, Sidecar, SidecarData } from './types.js';
6
+ /**
7
+ * The response object for DID Resolution.
8
+ */
9
+ export interface DidResolutionResponse {
10
+ didDocument: DidDocument;
11
+ metadata: {
12
+ confirmations?: number;
13
+ versionId: string;
14
+ updated?: string;
15
+ deactivated?: boolean;
16
+ };
17
+ }
18
+ /** The resolver needs a genesis document whose hash matches genesisHash. */
19
+ export interface NeedGenesisDocument {
20
+ readonly kind: 'NeedGenesisDocument';
21
+ /** Base64url-encoded SHA-256 hash from the DID identifier's genesisBytes. */
22
+ readonly genesisHash: string;
23
+ }
24
+ /** The resolver needs beacon signals for these beacon service addresses. */
25
+ export interface NeedBeaconSignals {
26
+ readonly kind: 'NeedBeaconSignals';
27
+ /** The beacon services that need signal data. Pass directly to BeaconSignalDiscovery. */
28
+ readonly beaconServices: ReadonlyArray<BeaconService>;
29
+ }
30
+ /** The resolver needs a CAS Announcement whose canonical hash matches announcementHash. */
31
+ export interface NeedCASAnnouncement {
32
+ readonly kind: 'NeedCASAnnouncement';
33
+ /** Base64url-encoded canonical hash of the CAS Announcement. */
34
+ readonly announcementHash: string;
35
+ /** The beacon service that produced this signal. */
36
+ readonly beaconServiceId: string;
37
+ }
38
+ /** The resolver needs a SignedBTCR2Update whose canonical hash matches updateHash. */
39
+ export interface NeedSignedUpdate {
40
+ readonly kind: 'NeedSignedUpdate';
41
+ /** Base64url-encoded canonical hash of the signed update. */
42
+ readonly updateHash: string;
43
+ /** The beacon service that produced this signal. */
44
+ readonly beaconServiceId: string;
45
+ }
46
+ /** Discriminated union of all data the resolver may request from the caller. */
47
+ export type DataNeed = NeedGenesisDocument | NeedBeaconSignals | NeedCASAnnouncement | NeedSignedUpdate;
48
+ /**
49
+ * Output of {@link Resolver.resolve}. Analogous to Rust's `ResolverState` enum.
50
+ * Either the resolver needs data from the caller, or resolution is complete.
51
+ */
52
+ export type ResolverState = {
53
+ status: 'action-required';
54
+ needs: ReadonlyArray<DataNeed>;
55
+ } | {
56
+ status: 'resolved';
57
+ result: DidResolutionResponse;
58
+ };
59
+ /**
60
+ * Return type from {@link Beacon.processSignals}.
61
+ * Contains successfully resolved updates and any data needs that must be
62
+ * satisfied before the remaining signals can be processed.
63
+ */
64
+ export interface BeaconProcessResult {
65
+ updates: Array<[SignedBTCR2Update, BlockMetadata]>;
66
+ needs: Array<DataNeed>;
67
+ }
68
+ /**
69
+ * Sans-I/O state machine for did:btcr2 resolution.
70
+ *
71
+ * Created by {@link DidBtcr2.resolve} (the factory). The caller drives resolution
72
+ * by repeatedly calling {@link resolve} and {@link provide}:
73
+ *
74
+ * ```typescript
75
+ * const resolver = DidBtcr2.resolve(did, { sidecar });
76
+ * let state = resolver.resolve();
77
+ *
78
+ * while (state.status === 'action-required') {
79
+ * for (const need of state.needs) { ... fetch & provide ... }
80
+ * state = resolver.resolve();
81
+ * }
82
+ * const { didDocument, metadata } = state.result;
83
+ * ```
84
+ *
85
+ * The Resolver performs **zero I/O**. All external data (Bitcoin signals, CAS
86
+ * data, genesis documents) flows through the advance/provide protocol.
87
+ *
88
+ * @class Resolver
89
+ */
90
+ export declare class Resolver {
91
+ #private;
92
+ /**
93
+ * @internal — Use {@link DidBtcr2.resolve} to create instances.
94
+ */
95
+ constructor(didComponents: DidComponents, sidecarData: SidecarData, currentDocument: DidDocument | null, options?: {
96
+ versionId?: string;
97
+ versionTime?: string;
98
+ genesisDocument?: object;
99
+ });
100
+ /**
101
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#if-genesis_bytes-is-a-secp256k1-public-key | 7.2.d.1 if genesis bytes is a secp256k1 Public Key}.
102
+ * @param {DidComponents} didComponents The decoded components of the did.
103
+ * @returns {DidDocument} The resolved DID Document object.
104
+ */
105
+ static deterministic(didComponents: DidComponents): DidDocument;
106
+ /**
107
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#if-genesis_bytes-is-a-sha-256-hash | 7.2.d.2 if genesis_bytes is a SHA-256 Hash}.
108
+ * @param {DidComponents} didComponents BTCR2 DID components used to resolve the DID Document
109
+ * @param {object} genesisDocument The genesis document for resolving the DID Document.
110
+ * @returns {DidDocument} The resolved DID Document object
111
+ * @throws {ResolveError} InvalidDidDocument if not conformant to DID Core v1.1
112
+ */
113
+ static external(didComponents: DidComponents, genesisDocument: object): DidDocument;
114
+ /**
115
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process-sidecar-data | Process Sidecar Data}
116
+ * @param {Sidecar} sidecar The sidecar data to process.
117
+ * @returns {SidecarData} The processed sidecar data containing maps of updates, CAS announcements, and SMT proofs.
118
+ */
119
+ static sidecarData(sidecar?: Sidecar): SidecarData;
120
+ /**
121
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process-updates | 7.2.f Process updates Array}.
122
+ * @param {DidDocument} currentDocument The current DID Document to apply the updates to.
123
+ * @param {Array<[SignedBTCR2Update, BlockMetadata]>} unsortedUpdates The unsorted array of BTCR2 Signed Updates and their associated Block Metadata.
124
+ * @param {string} [versionTime] The optional version time to limit updates to.
125
+ * @param {string} [versionId] The optional version id to limit updates to.
126
+ * @returns {DidResolutionResponse} The updated DID Document, number of confirmations, and version id.
127
+ */
128
+ static updates(currentDocument: DidDocument, unsortedUpdates: Array<[SignedBTCR2Update, BlockMetadata]>, versionTime?: string, versionId?: string): DidResolutionResponse;
129
+ /**
130
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/#confirm-duplicate-update | 7.2.f.1 Confirm Duplicate Update}.
131
+ * This step confirms that an update with a lower-than-expected targetVersionId is a true duplicate.
132
+ * @param {SignedBTCR2Update} update The BTCR2 Signed Update to confirm as a duplicate.
133
+ * @param {string[]} updateHashHistory The accumulated hash history for comparison.
134
+ * @returns {void} Does not return a value, but throws an error if the update is not a valid duplicate.
135
+ */
136
+ private static confirmDuplicate;
137
+ /**
138
+ * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#apply-update | 7.2.f.3 Apply Update}.
139
+ * @param {DidDocument} currentDocument The current DID Document to apply the update to.
140
+ * @param {SignedBTCR2Update} update The BTCR2 Signed Update to apply.
141
+ * @returns {DidDocument} The updated DID Document after applying the update.
142
+ * @throws {ResolveError} If the update is invalid or cannot be applied.
143
+ */
144
+ private static applyUpdate;
145
+ /**
146
+ * Advance the state machine. Returns either:
147
+ * - `{ status: 'action-required', needs }` — caller must provide data via {@link provide}
148
+ * - `{ status: 'resolved', result }` — resolution complete
149
+ *
150
+ * Analogous to Rust's `Resolver::resolve()`.
151
+ */
152
+ resolve(): ResolverState;
153
+ /**
154
+ * Provide data the resolver requested in a previous {@link resolve} call.
155
+ * Call once per need, then call {@link resolve} again to continue.
156
+ *
157
+ * Analogous to Rust's `Resolver::process_responses()`.
158
+ *
159
+ * @param need The DataNeed being fulfilled (from the `needs` array).
160
+ * @param data The data payload corresponding to the need kind.
161
+ */
162
+ provide(need: NeedGenesisDocument, data: object): void;
163
+ provide(need: NeedBeaconSignals, data: Map<BeaconService, Array<BeaconSignal>>): void;
164
+ provide(need: NeedCASAnnouncement, data: CASAnnouncement): void;
165
+ provide(need: NeedSignedUpdate, data: SignedBTCR2Update): void;
166
+ }
167
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":"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"}
@@ -23,10 +23,10 @@ export declare class Update {
23
23
  * @param {Btcr2DidDocument} sourceDocument The source DID document to be updated.
24
24
  * @param {PatchOperation[]} patches The array of JSON Patch operations to apply to the sourceDocument.
25
25
  * @param {number} sourceVersionId The version ID of the source document.
26
- * @returns {Promise<SignedBTCR2Update>} The constructed SignedBTCR2Update object.
26
+ * @returns {UnsignedBTCR2Update} The constructed UnsignedBTCR2Update object.
27
27
  * @throws {UpdateError} InvalidDid if sourceDocument.id does not match identifier.
28
28
  */
29
- static construct(sourceDocument: Btcr2DidDocument, patches: PatchOperation[], sourceVersionId: number): Promise<UnsignedBTCR2Update>;
29
+ static construct(sourceDocument: Btcr2DidDocument, patches: PatchOperation[], sourceVersionId: number): UnsignedBTCR2Update;
30
30
  /**
31
31
  * Implements subsection {@link http://dcdpr.github.io/did-btcr2/operations/update.html#construct-btcr2-signed-update | 7.3.c Construct BTCR2 Signed Update }.
32
32
  * This process constructs a BTCR2 Signed Update from a BTCR2 Unsigned Update.
@@ -37,7 +37,7 @@ export declare class Update {
37
37
  * @returns {SignedBTCR2Update} Did update payload secured with a proof => SignedBTCR2Update
38
38
  * @throws {UpdateError} if the privateKeyBytes are invalid
39
39
  */
40
- static sign(did: string, unsignedUpdate: UnsignedBTCR2Update, verificationMethod: DidVerificationMethod, secretKey: KeyBytes): Promise<SignedBTCR2Update>;
40
+ static sign(did: string, unsignedUpdate: UnsignedBTCR2Update, verificationMethod: DidVerificationMethod, secretKey: KeyBytes): SignedBTCR2Update;
41
41
  /**
42
42
  * Implements subsection {@link https://dcdpr.github.io/did-btcr2/operations/update.html#announce-did-update | 7.3.d Announce DID Update}.
43
43
  * BTCR2 Signed Updates are announced to the Bitcoin blockchain depending on the Beacon Type.
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/core/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,QAAQ,EACR,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAe,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEhG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;IACjB;;;;;;;;;OASG;WACU,SAAS,CACpB,cAAc,EAAE,gBAAgB,EAChC,OAAO,EAAE,cAAc,EAAE,EACzB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,mBAAmB,CAAC;IAoC/B;;;;;;;;;OASG;WACU,IAAI,CACf,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,mBAAmB,EACnC,kBAAkB,EAAE,qBAAqB,EACzC,SAAS,EAAE,QAAQ,GAClB,OAAO,CAAC,iBAAiB,CAAC;IAgC7B;;;;;;;;OAQG;WACU,QAAQ,CACnB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,iBAAiB,EACzB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC;CAU9B"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/core/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,QAAQ,EACR,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAGL,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAe,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEhG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;IACjB;;;;;;;;;OASG;IACH,MAAM,CAAC,SAAS,CACd,cAAc,EAAE,gBAAgB,EAChC,OAAO,EAAE,cAAc,EAAE,EACzB,eAAe,EAAE,MAAM,GACtB,mBAAmB;IAoCtB;;;;;;;;;OASG;IACH,MAAM,CAAC,IAAI,CACT,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,mBAAmB,EACnC,kBAAkB,EAAE,qBAAqB,EACzC,SAAS,EAAE,QAAQ,GAClB,iBAAiB;IAgCpB;;;;;;;;OAQG;WACU,QAAQ,CACnB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,iBAAiB,EACzB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC;CAU9B"}
@@ -1,10 +1,10 @@
1
1
  import { BitcoinConnection } from '@did-btcr2/bitcoin';
2
2
  import { DocumentBytes, HexString, KeyBytes, PatchOperation } from '@did-btcr2/common';
3
3
  import { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
4
- import { DidMethod, DidResolutionResult } from '@web5/dids';
4
+ import { DidMethod } from '@web5/dids';
5
5
  import { ResolutionOptions } from './core/interfaces.js';
6
+ import { Resolver } from './core/resolver.js';
6
7
  import { Btcr2DidDocument, DidVerificationMethod } from './utils/did-document.js';
7
- export type Btcr2Identifier = string;
8
8
  export interface DidCreateOptions {
9
9
  /** Type of identifier to create (key or external) */
10
10
  idType: string;
@@ -39,7 +39,7 @@ export declare class DidBtcr2 implements DidMethod {
39
39
  * @param {string} options.idType The type of identifier to create, either 'KEY' or 'EXTERNAL'. Defaults to 'KEY'.
40
40
  * @param {number} options.version The version number of the did:btcr2 specification to use for creating the identifier. Defaults to 1.
41
41
  * @param {string} options.network The Bitcoin network to use for the identifier, e.g. 'bitcoin', 'testnet', etc. Defaults to 'bitcoin'.
42
- * @returns {Promise<Btcr2Identifier>} Promise resolving to a Btcr2Identifier string.
42
+ * @returns {Promise<string>} Promise resolving to an identifier string.
43
43
  * @throws {MethodError} if any of the checks fail
44
44
  * @example
45
45
  * ```ts
@@ -47,29 +47,29 @@ export declare class DidBtcr2 implements DidMethod {
47
47
  * const did = DidBtcr2.create(genesisBytes, { idType: 'KEY', network: 'regtest' });
48
48
  * ```
49
49
  */
50
- static create(genesisBytes: KeyBytes | DocumentBytes, options?: DidCreateOptions): Btcr2Identifier;
50
+ static create(genesisBytes: KeyBytes | DocumentBytes, options?: DidCreateOptions): string;
51
51
  /**
52
52
  * Entry point for section {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html | 7.2 Resolve}.
53
- * See specification for the {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process | Resolve Process}.
54
- * See {@link Resolve | Resolve (class)} for class implementation.
55
53
  *
56
- * Resolving a did:btcr2 identifier iteratively builds a DID document by applying
57
- * BTCR2 Updates to an Initial DID Document that have been committed to the Bitcoin
58
- * blockchain by Authorized Beacon Signals. The Initial DID Document is either
59
- * deterministically created from the DID or provided by Sidecar Data.
54
+ * Factory method that performs pure setup and returns a {@link Resolver} state machine.
55
+ * The caller drives resolution by calling `resolver.resolve()` and `resolver.provide()`.
56
+ * Analogous to Rust's `Document::read()`.
60
57
  *
61
58
  * @param {string} did The did:btcr2 identifier to be resolved.
62
59
  * @param {ResolutionOptions} resolutionOptions Options used during the resolution process.
63
- * @returns {Promise<DidResolutionResult>} Promise resolving to a DID Resolution Result containing the `targetDocument`
64
- * @throws {ResolveError} If the resolution process fails at any step.
60
+ * @returns {Resolver} A sans-I/O state machine the caller drives to completion.
65
61
  * @example
66
62
  * ```ts
67
- * const resolution = await DidBtcr2.resolve(
68
- * 'did:btcr2:k1qgpr45cheptyjekl3cex80xfnkwhxnlclecwwf92gvdjrszm2uwhzlcxu5xte'
69
- * )
63
+ * const resolver = DidBtcr2.resolve(did, { sidecar });
64
+ * let state = resolver.resolve();
65
+ * while (state.status === 'action-required') {
66
+ * for (const need of state.needs) { ... provide data ... }
67
+ * state = resolver.resolve();
68
+ * }
69
+ * const { didDocument, metadata } = state.result;
70
70
  * ```
71
71
  */
72
- static resolve(did: string, resolutionOptions?: ResolutionOptions): Promise<DidResolutionResult>;
72
+ static resolve(did: string, resolutionOptions?: ResolutionOptions): Resolver;
73
73
  /**
74
74
  * Entry point for section {@link https://dcdpr.github.io/did-btcr2/#read | 7.3 Update}.
75
75
  * See specification for the {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process | Resolve Process}.
@@ -1 +1 @@
1
- {"version":3,"file":"did-btcr2.d.ts","sourceRoot":"","sources":["../../src/did-btcr2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,SAAS,EAIT,QAAQ,EAKR,cAAc,EAGf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAIL,SAAS,EACT,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAElF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,YAAW,SAAS;IACxC;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,CAAW;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe;IAelG;;;;;;;;;;;;;;;;;;;;OAoBG;WACU,OAAO,CAClB,GAAG,EAAE,MAAM,EACX,iBAAiB,GAAE,iBAAsB,GACxC,OAAO,CAAC,mBAAmB,CAAC;IAyG/B;;;;;;;;;;;;;;;;;;;OAmBG;WACU,MAAM,CAAC,EAClB,cAAc,EACd,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,OAAO,GACR,EAAE;QACD,cAAc,EAAE,gBAAgB,CAAC;QACjC,OAAO,EAAE,cAAc,EAAE,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;QACxB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;QACvC,OAAO,CAAC,EAAE,iBAAiB,CAAC;KAC7B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoF9B;;;;;;;;;OASG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,EAAG,QAAQ,CAAC,EAAE,MAAM,GAAG,qBAAqB;CA0BlG"}
1
+ {"version":3,"file":"did-btcr2.d.ts","sourceRoot":"","sources":["../../src/did-btcr2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,SAAS,EAIT,QAAQ,EAGR,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAIL,SAAS,EACV,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAElF,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,YAAW,SAAS;IACxC;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,CAAW;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM;IAezF;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,OAAO,CACZ,GAAG,EAAE,MAAM,EACX,iBAAiB,GAAE,iBAAsB,GACxC,QAAQ;IAsBX;;;;;;;;;;;;;;;;;;;OAmBG;WACU,MAAM,CAAC,EAClB,cAAc,EACd,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,eAAe,EACf,OAAO,GACR,EAAE;QACD,cAAc,EAAE,gBAAgB,CAAC;QACjC,OAAO,EAAE,cAAc,EAAE,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;QACxB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;QACvC,OAAO,CAAC,EAAE,iBAAiB,CAAC;KAC7B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoF9B;;;;;;;;;OASG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,EAAG,QAAQ,CAAC,EAAE,MAAM,GAAG,qBAAqB;CA0BlG"}
@@ -28,12 +28,12 @@ export * from './core/beacon/error.js';
28
28
  export * from './core/beacon/factory.js';
29
29
  export * from './core/beacon/interfaces.js';
30
30
  export * from './core/beacon/signal-discovery.js';
31
- export * from './core/beacon/singleton.js';
31
+ export * from './core/beacon/singleton-beacon.js';
32
32
  export * from './core/beacon/smt-beacon.js';
33
33
  export * from './core/beacon/utils.js';
34
34
  export * from './core/identifier.js';
35
35
  export * from './core/interfaces.js';
36
- export * from './core/resolve.js';
36
+ export * from './core/resolver.js';
37
37
  export * from './core/types.js';
38
38
  export * from './core/update.js';
39
39
  export * from './utils/appendix.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,4CAA4C,CAAC;AAE3D,cAAc,mDAAmD,CAAC;AAClE,cAAc,wDAAwD,CAAC;AACvE,cAAc,oDAAoD,CAAC;AACnE,cAAc,gEAAgE,CAAC;AAC/E,cAAc,mEAAmE,CAAC;AAClF,cAAc,kEAAkE,CAAC;AACjF,cAAc,mEAAmE,CAAC;AAClF,cAAc,4DAA4D,CAAC;AAC3E,cAAc,oEAAoE,CAAC;AACnF,cAAc,yEAAyE,CAAC;AACxF,cAAc,sEAAsE,CAAC;AACrF,cAAc,qEAAqE,CAAC;AACpF,cAAc,2EAA2E,CAAC;AAE1F,cAAc,6DAA6D,CAAC;AAC5E,cAAc,0DAA0D,CAAC;AAEzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,oDAAoD,CAAC;AACnE,cAAc,oDAAoD,CAAC;AAEnE,cAAc,0CAA0C,CAAC;AACzD,cAAc,0CAA0C,CAAC;AACzD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,6CAA6C,CAAC;AAE5D,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAExC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAC;AAC1D,cAAc,4CAA4C,CAAC;AAE3D,cAAc,mDAAmD,CAAC;AAClE,cAAc,wDAAwD,CAAC;AACvE,cAAc,oDAAoD,CAAC;AACnE,cAAc,gEAAgE,CAAC;AAC/E,cAAc,mEAAmE,CAAC;AAClF,cAAc,kEAAkE,CAAC;AACjF,cAAc,mEAAmE,CAAC;AAClF,cAAc,4DAA4D,CAAC;AAC3E,cAAc,oEAAoE,CAAC;AACnF,cAAc,yEAAyE,CAAC;AACxF,cAAc,sEAAsE,CAAC;AACrF,cAAc,qEAAqE,CAAC;AACpF,cAAc,2EAA2E,CAAC;AAE1F,cAAc,6DAA6D,CAAC;AAC5E,cAAc,0DAA0D,CAAC;AAEzE,cAAc,kDAAkD,CAAC;AACjE,cAAc,oDAAoD,CAAC;AACnE,cAAc,oDAAoD,CAAC;AAEnE,cAAc,0CAA0C,CAAC;AACzD,cAAc,0CAA0C,CAAC;AACzD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,6CAA6C,CAAC;AAE5D,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAExC,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@did-btcr2/method",
3
- "version": "0.24.1",
3
+ "version": "0.25.2",
4
4
  "type": "module",
5
5
  "description": "Reference implementation for the did:btcr2 DID method written in TypeScript and JavaScript. did:btcr2 is a censorship resistant DID Method using the Bitcoin blockchain as a Verifiable Data Registry to announce changes to the DID document. This is the core method implementation for the did-btcr2-js monorepo.",
6
6
  "main": "./dist/cjs/index.js",
@@ -82,11 +82,10 @@
82
82
  "helia": "^5.2.1",
83
83
  "multiformats": "^13.3.1",
84
84
  "nostr-tools": "^2.15.0",
85
- "tiny-secp256k1": "^2.2.3",
86
- "@did-btcr2/common": "7.0.0",
87
- "@did-btcr2/cryptosuite": "6.0.2",
88
- "@did-btcr2/keypair": "0.11.0",
89
- "@did-btcr2/bitcoin": "0.5.0"
85
+ "@did-btcr2/common": "8.0.0",
86
+ "@did-btcr2/cryptosuite": "6.0.4",
87
+ "@did-btcr2/keypair": "0.11.2",
88
+ "@did-btcr2/bitcoin": "0.5.1"
90
89
  },
91
90
  "devDependencies": {
92
91
  "@eslint/js": "^9.22.0",
@@ -1,3 +1,4 @@
1
+ import { hexToBytes } from '@noble/hashes/utils';
1
2
  import { keyAggExport, keyAggregate, sortKeys } from '@scure/btc-signer/musig2';
2
3
  import { payments, Transaction } from 'bitcoinjs-lib';
3
4
  import { BeaconCoordinatorError } from '../../error.js';
@@ -133,7 +134,7 @@ export class AggregateBeaconCohort implements BeaconCohort {
133
134
  );
134
135
  }
135
136
  }
136
- this.cohortKeys = cohortKeys.map(key => Buffer.from(key, 'hex'));
137
+ this.cohortKeys = cohortKeys.map(key => hexToBytes(key));
137
138
  const calculatedAddress = this.calulateBeaconAddress();
138
139
  if (calculatedAddress !== beaconAddress) {
139
140
  this.status = COHORT_STATUS.COHORT_FAILED;
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Did } from '@did-btcr2/common';
4
4
  import { CompressedSecp256k1PublicKey, RawSchnorrKeyPair, SchnorrKeyPair, Secp256k1SecretKey } from '@did-btcr2/keypair';
5
+ import { bytesToHex } from '@noble/hashes/utils';
5
6
  import { nonceGen } from '@scure/btc-signer/musig2';
6
7
  import { Event, EventTemplate, Filter, finalizeEvent, nip44 } from 'nostr-tools';
7
8
  import { SimplePool } from 'nostr-tools/pool';
@@ -217,10 +218,10 @@ export class NostrAdapter implements CommunicationService {
217
218
  // this.config.coordinatorDids.push(recipient);
218
219
  // }
219
220
 
220
- const tags = [['p', Buffer.from(sender.x).toString('hex')]];
221
+ const tags = [['p', bytesToHex(sender.x)]];
221
222
  if(to) {
222
223
  const recipient = new CompressedSecp256k1PublicKey(Identifier.decode(to).genesisBytes);
223
- tags.push(['p', Buffer.from(recipient.x).toString('hex')]);
224
+ tags.push(['p', bytesToHex(recipient.x)]);
224
225
  }
225
226
  const { type } = message as any ?? {};
226
227
  if(!type) {
@@ -1,5 +1,6 @@
1
1
  import { Maybe } from '@did-btcr2/common';
2
2
  import { RawSchnorrKeyPair } from '@did-btcr2/keypair';
3
+ import { bytesToHex } from '@noble/hashes/utils';
3
4
  import { BeaconCoordinatorError } from '../error.js';
4
5
  import { AggregateBeaconCohort } from './cohort/index.js';
5
6
  import {
@@ -253,7 +254,7 @@ export class BeaconCoordinator {
253
254
 
254
255
  if (signingSession.status === SIGNING_SESSION_STATUS.PARTIAL_SIGNATURES_RECEIVED) {
255
256
  const signature = await signingSession.generateFinalSignature();
256
- console.info(`Final signature ${Buffer.from(signature).toString('hex')} generated for session ${signingSession.id}`);
257
+ console.info(`Final signature ${bytesToHex(signature)} generated for session ${signingSession.id}`);
257
258
  }
258
259
  }
259
260
 
@@ -1,4 +1,5 @@
1
1
  import { KeyBytes, Maybe } from '@did-btcr2/common';
2
+ import { bytesToHex } from '@noble/hashes/utils';
2
3
  import { HDKey } from '@scure/bip32';
3
4
  import { mnemonicToSeedSync } from '@scure/bip39';
4
5
  import * as musig2 from '@scure/btc-signer/musig2';
@@ -280,7 +281,7 @@ export class BeaconParticipant {
280
281
  console.error(`Failed to derive public key for cohort ${cohortId}`);
281
282
  return;
282
283
  }
283
- const participantPk = Buffer.from(participantPkBytes).toString('hex');
284
+ const participantPk = bytesToHex(participantPkBytes);
284
285
  const beaconAddress = cohortSetMessage.body?.beaconAddress;
285
286
  if(!beaconAddress) {
286
287
  console.error(`Beacon address not provided in cohort set message for ${cohortId}`);
@@ -291,7 +292,7 @@ export class BeaconParticipant {
291
292
  console.error(`Cohort keys not provided in cohort set message for ${cohortId}`);
292
293
  return;
293
294
  }
294
- const keys = cohortKeys.map(key => Buffer.from(key).toString('hex'));
295
+ const keys = cohortKeys.map(key => bytesToHex(new Uint8Array(key)));
295
296
  cohort.validateCohort([participantPk], keys, beaconAddress);
296
297
  console.info(`BeaconParticipant w/ pk ${participantPk} successfully joined cohort ${cohortId} with beacon address ${beaconAddress}.`);
297
298
  console.info(`Cohort status: ${cohort.status}`);
@@ -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,10 @@
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 { hexToBytes } from '@noble/hashes/utils';
6
+ import { opcodes, Psbt, script } from 'bitcoinjs-lib';
7
+ import type { BeaconProcessResult, DataNeed } from '../resolver.js';
4
8
  import { SidecarData } from '../types.js';
5
9
  import { Beacon } from './beacon.js';
6
10
  import { CASBeaconError } from './error.js';
@@ -8,6 +12,13 @@ import { BeaconService, BeaconSignal, BlockMetadata } from './interfaces.js';
8
12
 
9
13
  /**
10
14
  * Implements {@link https://dcdpr.github.io/did-btcr2/terminology.html#cas-beacon | CAS Beacon}.
15
+ *
16
+ * A CAS (Content-Addressed Store) Beacon aggregates updates for multiple DIDs
17
+ * into a single CAS Announcement — a mapping of DIDs to their update hashes.
18
+ * The hash of the CAS Announcement is broadcast on-chain via OP_RETURN.
19
+ * During resolution, the CAS Announcement is retrieved from the sidecar (or CAS)
20
+ * and used to look up the individual signed update for the DID being resolved.
21
+ *
11
22
  * @class CASBeacon
12
23
  * @type {CASBeacon}
13
24
  * @extends {Beacon}
@@ -23,31 +34,167 @@ export class CASBeacon extends Beacon {
23
34
 
24
35
  /**
25
36
  * Implements {@link https://dcdpr.github.io/did-btcr2/operations/resolve.html#process-cas-beacon | 7.2.e.1 Process CAS Beacon}.
37
+ *
38
+ * For each signal, the signalBytes contain the hex-encoded hash of a CAS Announcement.
39
+ * The CAS Announcement maps DIDs to their base64url-encoded update hashes.
40
+ * This method looks up the CAS Announcement from the sidecar, extracts the update
41
+ * hash for the DID being resolved, and retrieves the corresponding signed update.
42
+ *
26
43
  * @param {Array<BeaconSignal>} signals The array of Beacon Signals to process.
27
44
  * @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.
45
+ * @returns {BeaconProcessResult} Successfully resolved updates and any data needs.
46
+ * @throws {CASBeaconError} if hash verification fails (validation errors only).
30
47
  */
31
48
  processSignals(
32
49
  signals: Array<BeaconSignal>,
33
50
  sidecar: SidecarData
34
- ): Promise<Array<[SignedBTCR2Update, BlockMetadata]>> {
35
- throw new CASBeaconError('Method not implemented.', `METHOD_NOT_IMPLEMENTED`, { signals, sidecar });
51
+ ): BeaconProcessResult {
52
+ const updates = new Array<[SignedBTCR2Update, BlockMetadata]>();
53
+ const needs = new Array<DataNeed>();
54
+
55
+ // Extract the DID from the beacon service id (strip the #fragment)
56
+ const did = this.service.id.split('#')[0];
57
+
58
+ for(const signal of signals) {
59
+ // Decode signal bytes from hex and re-encode to base64url for sidecar lookup
60
+ const announcementHash = encode(decode(signal.signalBytes, 'hex'));
61
+
62
+ // Look up the CAS Announcement in sidecar casMap
63
+ const casAnnouncement = sidecar.casMap.get(announcementHash);
64
+
65
+ if(!casAnnouncement) {
66
+ // CAS Announcement not available — emit a need
67
+ needs.push({
68
+ kind : 'NeedCASAnnouncement',
69
+ announcementHash,
70
+ beaconServiceId : this.service.id
71
+ });
72
+ continue;
73
+ }
74
+
75
+ // Look up this DID's update hash in the CAS Announcement
76
+ const updateHash = casAnnouncement[did];
77
+
78
+ // If no entry for this DID, this announcement doesn't contain an update for us — skip
79
+ if(!updateHash) {
80
+ continue;
81
+ }
82
+
83
+ // Look up the signed update in sidecar updateMap
84
+ const signedUpdate = sidecar.updateMap.get(updateHash);
85
+
86
+ if(!signedUpdate) {
87
+ // Signed update not available — emit a need
88
+ needs.push({
89
+ kind : 'NeedSignedUpdate',
90
+ updateHash,
91
+ beaconServiceId : this.service.id
92
+ });
93
+ continue;
94
+ }
95
+
96
+ updates.push([signedUpdate, signal.blockMetadata]);
97
+ }
98
+
99
+ return { updates, needs };
36
100
  }
37
101
 
38
102
  /**
39
- * Broadcast CAS Beacon signal to the Bitcoin network.
103
+ * Broadcasts a CAS Beacon signal to the Bitcoin network.
104
+ *
105
+ * Creates a CAS Announcement mapping the DID to the update hash, then broadcasts
106
+ * the hash of the announcement via OP_RETURN. The CAS Announcement is distributed
107
+ * to resolvers via sidecar data.
108
+ *
40
109
  * @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
41
110
  * @param {KeyBytes} secretKey The secret key for signing the Bitcoin transaction.
42
111
  * @param {BitcoinConnection} bitcoin The Bitcoin network connection.
43
- * @return {Promise<SignedBTCR2Update>} The signed update that was broadcasted.
44
- * @throws {CASBeaconError} if broadcasting fails.
112
+ * @returns {Promise<SignedBTCR2Update>} The signed update that was broadcast.
113
+ * @throws {CASBeaconError} if the bitcoin address is invalid or unfunded.
45
114
  */
46
115
  async broadcastSignal(
47
116
  signedUpdate: SignedBTCR2Update,
48
117
  secretKey: KeyBytes,
49
118
  bitcoin: BitcoinConnection
50
119
  ): Promise<SignedBTCR2Update> {
51
- throw new CASBeaconError('Method not implemented.', `METHOD_NOT_IMPLEMENTED`, {signedUpdate, secretKey, bitcoin});
120
+ // Extract the DID from the beacon service id (strip the #fragment)
121
+ const did = this.service.id.split('#')[0];
122
+
123
+ // Hash the signed update (base64url for the CAS Announcement entry)
124
+ const updateHash = canonicalHash(signedUpdate);
125
+
126
+ // Create the CAS Announcement mapping this DID to its update hash
127
+ const casAnnouncement = { [did]: updateHash };
128
+
129
+ // TODO: Publish CAS Announcement to content-addressed store (e.g., IPFS via Helia)
130
+
131
+ // Canonicalize and hash the CAS Announcement for the OP_RETURN output
132
+ const announcementHash = hash(canonicalize(casAnnouncement));
133
+
134
+ // Convert the serviceEndpoint to a bitcoin address by removing the 'bitcoin:' prefix
135
+ const bitcoinAddress = this.service.serviceEndpoint.replace('bitcoin:', '');
136
+
137
+ // Query the Bitcoin network for UTXOs associated with the bitcoinAddress
138
+ const utxos = await bitcoin.rest.address.getUtxos(bitcoinAddress);
139
+
140
+ // If no utxos are found, throw an error indicating the address is unfunded.
141
+ if(!utxos.length) {
142
+ throw new CASBeaconError(
143
+ 'No UTXOs found, please fund address!',
144
+ 'UNFUNDED_BEACON_ADDRESS', { bitcoinAddress }
145
+ );
146
+ }
147
+
148
+ // Sort utxos by block height and take the most recent one
149
+ const utxo: AddressUtxo | undefined = utxos.sort(
150
+ (a, b) => b.status.block_height - a.status.block_height
151
+ ).shift();
152
+
153
+ // If no utxos are found, throw an error.
154
+ if(!utxo) {
155
+ throw new CASBeaconError(
156
+ 'Beacon bitcoin address unfunded or utxos unconfirmed.',
157
+ 'UNFUNDED_BEACON_ADDRESS', { bitcoinAddress }
158
+ );
159
+ }
160
+
161
+ // Get the previous tx to the utxo being spent
162
+ const prevTx = await bitcoin.rest.transaction.getHex(utxo.txid);
163
+
164
+ // Construct a spend transaction
165
+ const spendTx = new Psbt({ network: bitcoin.data })
166
+ // Spend tx contains the utxo as its input
167
+ .addInput({
168
+ hash : utxo.txid,
169
+ index : utxo.vout,
170
+ nonWitnessUtxo : hexToBytes(prevTx)
171
+ })
172
+ // Add a change output minus a fee of 500 sats
173
+ // TODO: calculate fee based on transaction vsize and current fee rates
174
+ .addOutput({ address: bitcoinAddress, value: BigInt(utxo.value) - BigInt(500) })
175
+ // Add an OP_RETURN output containing the CAS Announcement hash
176
+ .addOutput({ script: script.compile([opcodes.OP_RETURN, announcementHash]), value: 0n });
177
+
178
+ // Construct a key pair and PSBT signer from the secret key
179
+ const keyPair = SchnorrKeyPair.fromSecret(secretKey);
180
+ const signer = {
181
+ publicKey : keyPair.publicKey.compressed,
182
+ sign : (hash: Uint8Array) => keyPair.secretKey.sign(hash, { scheme: 'ecdsa' }),
183
+ };
184
+
185
+ // Sign 0th input, finalize extract to hex in prep for broadcast
186
+ const signedTx = spendTx.signInput(0, signer)
187
+ .finalizeAllInputs()
188
+ .extractTransaction()
189
+ .toHex();
190
+
191
+ // Broadcast spendTx to the Bitcoin network.
192
+ const txid = await bitcoin.rest.transaction.send(signedTx);
193
+
194
+ // Log the txid of the broadcasted transaction
195
+ console.info(`CAS Beacon Signal Broadcasted with txid: ${txid}`);
196
+
197
+ // Return the signed update
198
+ return signedUpdate;
52
199
  }
53
200
  }