@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.
- package/dist/browser.js +1541 -26561
- package/dist/browser.mjs +1541 -26561
- package/dist/cjs/core/beacon/aggregation/cohort/index.js +2 -1
- package/dist/cjs/core/beacon/aggregation/cohort/index.js.map +1 -1
- package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js +3 -2
- package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
- package/dist/cjs/core/beacon/aggregation/coordinator.js +2 -1
- package/dist/cjs/core/beacon/aggregation/coordinator.js.map +1 -1
- package/dist/cjs/core/beacon/aggregation/participant.js +3 -2
- package/dist/cjs/core/beacon/aggregation/participant.js.map +1 -1
- package/dist/cjs/core/beacon/beacon.js.map +1 -1
- package/dist/cjs/core/beacon/cas-beacon.js +120 -7
- package/dist/cjs/core/beacon/cas-beacon.js.map +1 -1
- package/dist/cjs/core/beacon/factory.js +1 -1
- package/dist/cjs/core/beacon/factory.js.map +1 -1
- package/dist/cjs/core/beacon/signal-discovery.js +1 -1
- package/dist/cjs/core/beacon/signal-discovery.js.map +1 -1
- package/dist/cjs/core/beacon/{singleton.js → singleton-beacon.js} +20 -27
- package/dist/cjs/core/beacon/singleton-beacon.js.map +1 -0
- package/dist/cjs/core/beacon/smt-beacon.js +1 -1
- package/dist/cjs/core/beacon/smt-beacon.js.map +1 -1
- package/dist/{esm/core/resolve.js → cjs/core/resolver.js} +241 -93
- package/dist/cjs/core/resolver.js.map +1 -0
- package/dist/cjs/core/update.js +5 -5
- package/dist/cjs/core/update.js.map +1 -1
- package/dist/cjs/did-btcr2.js +39 -96
- package/dist/cjs/did-btcr2.js.map +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/core/beacon/aggregation/cohort/index.js +2 -1
- package/dist/esm/core/beacon/aggregation/cohort/index.js.map +1 -1
- package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +3 -2
- package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
- package/dist/esm/core/beacon/aggregation/coordinator.js +2 -1
- package/dist/esm/core/beacon/aggregation/coordinator.js.map +1 -1
- package/dist/esm/core/beacon/aggregation/participant.js +3 -2
- package/dist/esm/core/beacon/aggregation/participant.js.map +1 -1
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/cas-beacon.js +120 -7
- package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
- package/dist/esm/core/beacon/factory.js +1 -1
- package/dist/esm/core/beacon/factory.js.map +1 -1
- package/dist/esm/core/beacon/signal-discovery.js +1 -1
- package/dist/esm/core/beacon/signal-discovery.js.map +1 -1
- package/dist/esm/core/beacon/{singleton.js → singleton-beacon.js} +20 -27
- package/dist/esm/core/beacon/singleton-beacon.js.map +1 -0
- package/dist/esm/core/beacon/smt-beacon.js +1 -1
- package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
- package/dist/{cjs/core/resolve.js → esm/core/resolver.js} +241 -93
- package/dist/esm/core/resolver.js.map +1 -0
- package/dist/esm/core/update.js +5 -5
- package/dist/esm/core/update.js.map +1 -1
- package/dist/esm/did-btcr2.js +39 -96
- package/dist/esm/did-btcr2.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/beacon/aggregation/cohort/index.d.ts.map +1 -1
- package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +1 -1
- package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +1 -1
- package/dist/types/core/beacon/aggregation/participant.d.ts.map +1 -1
- package/dist/types/core/beacon/beacon.d.ts +9 -4
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/cas-beacon.d.ts +26 -7
- package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/{singleton.d.ts → singleton-beacon.d.ts} +7 -5
- package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -0
- package/dist/types/core/beacon/smt-beacon.d.ts +4 -3
- package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
- package/dist/types/core/interfaces.d.ts +5 -15
- package/dist/types/core/interfaces.d.ts.map +1 -1
- package/dist/types/core/resolver.d.ts +167 -0
- package/dist/types/core/resolver.d.ts.map +1 -0
- package/dist/types/core/update.d.ts +3 -3
- package/dist/types/core/update.d.ts.map +1 -1
- package/dist/types/did-btcr2.d.ts +16 -16
- package/dist/types/did-btcr2.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +5 -6
- package/src/core/beacon/aggregation/cohort/index.ts +2 -1
- package/src/core/beacon/aggregation/communication/adapter/nostr.ts +3 -2
- package/src/core/beacon/aggregation/coordinator.ts +2 -1
- package/src/core/beacon/aggregation/participant.ts +3 -2
- package/src/core/beacon/beacon.ts +9 -5
- package/src/core/beacon/cas-beacon.ts +157 -10
- package/src/core/beacon/factory.ts +1 -1
- package/src/core/beacon/signal-discovery.ts +1 -1
- package/src/core/beacon/{singleton.ts → singleton-beacon.ts} +21 -36
- package/src/core/beacon/smt-beacon.ts +4 -3
- package/src/core/interfaces.ts +5 -16
- package/src/core/{resolve.ts → resolver.ts} +355 -130
- package/src/core/update.ts +7 -7
- package/src/did-btcr2.ts +42 -132
- package/src/index.ts +2 -2
- package/dist/cjs/core/beacon/singleton.js.map +0 -1
- package/dist/cjs/core/resolve.js.map +0 -1
- package/dist/esm/core/beacon/singleton.js.map +0 -1
- package/dist/esm/core/resolve.js.map +0 -1
- package/dist/types/core/beacon/singleton.d.ts.map +0 -1
- package/dist/types/core/resolve.d.ts +0 -93
- 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":"AAcA,OAAO,EAIL,iBAAiB,EAElB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAE,WAAW,EAAwB,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEpF,OAAO,EAAE,aAAa,EAAc,MAAM,iBAAiB,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAA;CACF;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,yFAAyF;IACzF,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;CACvD;AAED,2FAA2F;AAC3F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,oDAAoD;IACpD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAExG;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,KAAK,CAAC,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC,CAAC;IACnD,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;CACxB;AAaD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,QAAQ;;IAmBnB;;OAEG;gBAED,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,WAAW,EACxB,eAAe,EAAE,WAAW,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE;IAmBlF;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAAC,aAAa,EAAE,aAAa,GAAG,WAAW;IA8B/D;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CACb,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,MAAM,GACtB,WAAW;IA2Bd;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,GAAE,OAAuB,GAAG,WAAW;IAyBjE;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,CACZ,eAAe,EAAE,WAAW,EAC5B,eAAe,EAAE,KAAK,CAAC,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC,EAC1D,WAAW,CAAC,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,qBAAqB;IA+GxB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAmB/B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAuF1B;;;;;;OAMG;IACH,OAAO,IAAI,aAAa;IAuIxB;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IACtD,OAAO,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI;IACrF,OAAO,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI;IAC/D,OAAO,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;CA6B/D"}
|
|
@@ -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 {
|
|
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):
|
|
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):
|
|
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;
|
|
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
|
|
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<
|
|
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):
|
|
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
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
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 {
|
|
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
|
|
68
|
-
*
|
|
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):
|
|
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,
|
|
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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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/
|
|
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,
|
|
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.
|
|
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
|
-
"
|
|
86
|
-
"@did-btcr2/
|
|
87
|
-
"@did-btcr2/
|
|
88
|
-
"@did-btcr2/
|
|
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 =>
|
|
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',
|
|
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',
|
|
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 ${
|
|
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 =
|
|
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 =>
|
|
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 '
|
|
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
|
|
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 {
|
|
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
|
-
):
|
|
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 {
|
|
29
|
-
* @throws {CASBeaconError} if
|
|
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
|
-
):
|
|
35
|
-
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
44
|
-
* @throws {CASBeaconError} if
|
|
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
|
-
|
|
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
|
}
|