@did-btcr2/method 0.28.0 → 0.29.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.js +20092 -31631
- package/dist/browser.mjs +20019 -31558
- package/dist/cjs/index.js +1164 -364
- package/dist/esm/core/aggregation/beacon-strategy.js +62 -0
- package/dist/esm/core/aggregation/beacon-strategy.js.map +1 -0
- package/dist/esm/core/aggregation/cohort.js +31 -8
- package/dist/esm/core/aggregation/cohort.js.map +1 -1
- package/dist/esm/core/aggregation/logger.js +15 -0
- package/dist/esm/core/aggregation/logger.js.map +1 -0
- package/dist/esm/core/aggregation/messages/base.js +12 -1
- package/dist/esm/core/aggregation/messages/base.js.map +1 -1
- package/dist/esm/core/aggregation/messages/bodies.js +90 -0
- package/dist/esm/core/aggregation/messages/bodies.js.map +1 -0
- package/dist/esm/core/aggregation/messages/factories.js.map +1 -1
- package/dist/esm/core/aggregation/messages/index.js +1 -0
- package/dist/esm/core/aggregation/messages/index.js.map +1 -1
- package/dist/esm/core/aggregation/participant.js +39 -46
- package/dist/esm/core/aggregation/participant.js.map +1 -1
- package/dist/esm/core/aggregation/runner/participant-runner.js +33 -7
- package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
- package/dist/esm/core/aggregation/runner/service-runner.js +198 -19
- package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
- package/dist/esm/core/aggregation/service.js +143 -15
- package/dist/esm/core/aggregation/service.js.map +1 -1
- package/dist/esm/core/aggregation/signing-session.js +44 -5
- package/dist/esm/core/aggregation/signing-session.js.map +1 -1
- package/dist/esm/core/aggregation/transport/didcomm.js +9 -0
- package/dist/esm/core/aggregation/transport/didcomm.js.map +1 -1
- package/dist/esm/core/aggregation/transport/nostr.js +245 -16
- package/dist/esm/core/aggregation/transport/nostr.js.map +1 -1
- package/dist/esm/core/beacon/beacon.js +147 -61
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/utils.js +14 -9
- package/dist/esm/core/beacon/utils.js.map +1 -1
- package/dist/esm/did-btcr2.js +0 -4
- package/dist/esm/did-btcr2.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/did-document.js +2 -2
- package/dist/esm/utils/did-document.js.map +1 -1
- package/dist/types/core/aggregation/beacon-strategy.d.ts +52 -0
- package/dist/types/core/aggregation/beacon-strategy.d.ts.map +1 -0
- package/dist/types/core/aggregation/cohort.d.ts +20 -3
- package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
- package/dist/types/core/aggregation/logger.d.ts +22 -0
- package/dist/types/core/aggregation/logger.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/base.d.ts +13 -1
- package/dist/types/core/aggregation/messages/base.d.ts.map +1 -1
- package/dist/types/core/aggregation/messages/bodies.d.ts +130 -0
- package/dist/types/core/aggregation/messages/bodies.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/factories.d.ts +1 -0
- package/dist/types/core/aggregation/messages/factories.d.ts.map +1 -1
- package/dist/types/core/aggregation/messages/index.d.ts +1 -0
- package/dist/types/core/aggregation/messages/index.d.ts.map +1 -1
- package/dist/types/core/aggregation/participant.d.ts +2 -0
- package/dist/types/core/aggregation/participant.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/events.d.ts +32 -6
- package/dist/types/core/aggregation/runner/events.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/participant-runner.d.ts +7 -5
- package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/service-runner.d.ts +33 -3
- package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
- package/dist/types/core/aggregation/service.d.ts +33 -2
- package/dist/types/core/aggregation/service.d.ts.map +1 -1
- package/dist/types/core/aggregation/signing-session.d.ts +5 -1
- package/dist/types/core/aggregation/signing-session.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/didcomm.d.ts +3 -0
- package/dist/types/core/aggregation/transport/didcomm.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/nostr.d.ts +99 -1
- package/dist/types/core/aggregation/transport/nostr.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/transport.d.ts +25 -0
- package/dist/types/core/aggregation/transport/transport.d.ts.map +1 -1
- package/dist/types/core/beacon/beacon.d.ts +85 -18
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/utils.d.ts +2 -2
- package/dist/types/core/beacon/utils.d.ts.map +1 -1
- package/dist/types/did-btcr2.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +5 -7
- package/src/core/aggregation/beacon-strategy.ts +123 -0
- package/src/core/aggregation/cohort.ts +34 -8
- package/src/core/aggregation/logger.ts +33 -0
- package/src/core/aggregation/messages/base.ts +20 -5
- package/src/core/aggregation/messages/bodies.ts +223 -0
- package/src/core/aggregation/messages/factories.ts +1 -0
- package/src/core/aggregation/messages/index.ts +1 -0
- package/src/core/aggregation/participant.ts +40 -46
- package/src/core/aggregation/runner/events.ts +27 -3
- package/src/core/aggregation/runner/participant-runner.ts +41 -7
- package/src/core/aggregation/runner/service-runner.ts +227 -19
- package/src/core/aggregation/service.ts +189 -20
- package/src/core/aggregation/signing-session.ts +65 -7
- package/src/core/aggregation/transport/didcomm.ts +17 -0
- package/src/core/aggregation/transport/nostr.ts +266 -23
- package/src/core/aggregation/transport/transport.ts +33 -0
- package/src/core/beacon/beacon.ts +217 -76
- package/src/core/beacon/utils.ts +16 -11
- package/src/did-btcr2.ts +0 -5
- package/src/index.ts +2 -0
- package/src/utils/did-document.ts +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Did } from '@did-btcr2/common';
|
|
2
2
|
import type { SchnorrKeyPair } from '@did-btcr2/keypair';
|
|
3
3
|
import { SimplePool } from 'nostr-tools/pool';
|
|
4
|
+
import type { Logger } from '../logger.js';
|
|
4
5
|
import type { BaseMessage } from '../messages/base.js';
|
|
5
6
|
import type { MessageHandler, Transport } from './transport.js';
|
|
6
7
|
/**
|
|
@@ -10,7 +11,24 @@ import type { MessageHandler, Transport } from './transport.js';
|
|
|
10
11
|
export declare const DEFAULT_NOSTR_RELAYS: string[];
|
|
11
12
|
export interface NostrTransportConfig {
|
|
12
13
|
relays?: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Optional logger for transport-level diagnostics (publish/subscribe events,
|
|
16
|
+
* relay rejections, parse failures). Defaults to {@link CONSOLE_LOGGER}.
|
|
17
|
+
*/
|
|
18
|
+
logger?: Logger;
|
|
19
|
+
/**
|
|
20
|
+
* How far back (in milliseconds) to set the `since` filter on the broadcast
|
|
21
|
+
* (COHORT_ADVERT) subscription. Some public relays do NOT replay historical
|
|
22
|
+
* events to late subscribers when the filter has no `since`, so the advert
|
|
23
|
+
* gets lost if the subscription lands after the publish. A short lookback
|
|
24
|
+
* window nudges those relays into delivering recent adverts. Set to 0 to
|
|
25
|
+
* disable the filter entirely (unbounded history). Defaults to
|
|
26
|
+
* {@link DEFAULT_BROADCAST_LOOKBACK_MS} (5 minutes).
|
|
27
|
+
*/
|
|
28
|
+
broadcastLookbackMs?: number;
|
|
13
29
|
}
|
|
30
|
+
/** Default `since` lookback for broadcast (COHORT_ADVERT) subscriptions: 5 minutes. */
|
|
31
|
+
export declare const DEFAULT_BROADCAST_LOOKBACK_MS: number;
|
|
14
32
|
/**
|
|
15
33
|
* Nostr Transport for did:btcr2 aggregation messages.
|
|
16
34
|
*
|
|
@@ -41,15 +59,95 @@ export declare class NostrTransport implements Transport {
|
|
|
41
59
|
* @example
|
|
42
60
|
* const transport = new NostrTransport();
|
|
43
61
|
* const keys = SchnorrKeyPair.generate();
|
|
44
|
-
*
|
|
62
|
+
* const did = DidBtcr2.create(keys.publicKey.compressed, { idType: 'KEY', network: 'mutinynet' });
|
|
63
|
+
* transport.registerActor(did, keys);
|
|
45
64
|
* transport.start();
|
|
46
65
|
*/
|
|
47
66
|
registerActor(did: string, keys: SchnorrKeyPair): void;
|
|
67
|
+
/**
|
|
68
|
+
* Detach an actor: drop its handlers, close its relay subscriptions, and remove its keys + peer
|
|
69
|
+
* mapping. Idempotent.
|
|
70
|
+
* @param {string} did - The DID of the actor to unregister.
|
|
71
|
+
* @returns {void}
|
|
72
|
+
* @throws {TransportAdapterError} If the transport is not started or if the pool is unavailable.
|
|
73
|
+
* @example
|
|
74
|
+
* transport.unregisterActor(did);
|
|
75
|
+
*/
|
|
76
|
+
unregisterActor(did: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Remove a single (actor, messageType) handler. Idempotent.
|
|
79
|
+
* @param {string} actorDid - The DID of the actor.
|
|
80
|
+
* @param {string} messageType - The type of message to unregister the handler for.
|
|
81
|
+
* @returns {void}
|
|
82
|
+
* @example
|
|
83
|
+
* transport.unregisterMessageHandler(actorDid, messageType);
|
|
84
|
+
*/
|
|
85
|
+
unregisterMessageHandler(actorDid: string, messageType: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Gets the public key for a registered actor by their DID.
|
|
88
|
+
* @param {string} did - The DID of the registered actor to get the public key for.
|
|
89
|
+
* @returns {Uint8Array | undefined} The compressed public key bytes for the actor's DID, or
|
|
90
|
+
* undefined if the DID is not registered.
|
|
91
|
+
*/
|
|
48
92
|
getActorPk(did: string): Uint8Array | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Registers a peer's communication public key for encrypted messages.
|
|
95
|
+
* @param {string} did - The DID of the peer to register.
|
|
96
|
+
* @param {Uint8Array} communicationPk - The compressed secp256k1 public key bytes for the peer.
|
|
97
|
+
*/
|
|
49
98
|
registerPeer(did: string, communicationPk: Uint8Array): void;
|
|
99
|
+
/**
|
|
100
|
+
* Gets the registered communication public key for a peer by their DID.
|
|
101
|
+
* @param {string} did - The DID of the peer to get the communication public key for.
|
|
102
|
+
* @returns {Uint8Array | undefined} The compressed secp256k1 public key bytes for the peer, or
|
|
103
|
+
* undefined if the peer is not registered.
|
|
104
|
+
*/
|
|
50
105
|
getPeerPk(did: string): Uint8Array | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Registers a message handler function for a specific actor and message type. The handler will be called
|
|
108
|
+
* when a message of the specified type is received for the actor's DID. The transport must have been
|
|
109
|
+
* started for handlers to be invoked. If the transport is already started, the handler will be registered
|
|
110
|
+
* immediately; otherwise, it will be registered when the transport starts and the actor's subscription is created.
|
|
111
|
+
* @param {string} actorDid - The DID of the actor to register the message handler for.
|
|
112
|
+
* @param {string} messageType - The type of message to handle.
|
|
113
|
+
* @param {MessageHandler} handler - The function to handle incoming messages of the specified type.
|
|
114
|
+
* @throws {TransportAdapterError} If the actor DID is not registered or if the handler is invalid.
|
|
115
|
+
*/
|
|
51
116
|
registerMessageHandler(actorDid: string, messageType: string, handler: MessageHandler): void;
|
|
117
|
+
/**
|
|
118
|
+
* Starts the transport by connecting to the configured Nostr relays and setting up subscriptions
|
|
119
|
+
* for all registered actors. This method must be called after registering actors via registerActor()
|
|
120
|
+
* and before sending or receiving messages. The transport will subscribe to broadcast events (kind 1)
|
|
121
|
+
* for cohort adverts and directed events (kinds 1 and 1059) for each registered actor based on their
|
|
122
|
+
* public keys. Incoming events are processed and dispatched to the appropriate handlers based on
|
|
123
|
+
* message type. If the transport is already started, this method has no effect.
|
|
124
|
+
* @returns {NostrTransport}
|
|
125
|
+
*/
|
|
52
126
|
start(): NostrTransport;
|
|
127
|
+
/**
|
|
128
|
+
* Sends a message by publishing a Nostr event to the configured relays. The message is serialized
|
|
129
|
+
* as JSON and included in the event content.
|
|
130
|
+
* @param {BaseMessage} message - The aggregation message to send. Must include a valid `type` property.
|
|
131
|
+
* @param {Did} sender - The DID of the registered actor sending the message. Must have been
|
|
132
|
+
* registered via registerActor().
|
|
133
|
+
* @param {Did} [to] - Optional recipient DID for directed messages. Required for encrypted message
|
|
134
|
+
* types. If provided, must have been registered via registerPeer().
|
|
135
|
+
* @returns {Promise<void>} Resolves when the message has been published to the relays. Note that
|
|
136
|
+
* publication is best-effort: the method will resolve as long as at least one relay accepts the
|
|
137
|
+
* event, even if others reject it.
|
|
138
|
+
*/
|
|
53
139
|
sendMessage(message: BaseMessage, sender: Did, to?: Did): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Publish the message once immediately and then re-publish on an interval
|
|
142
|
+
* until the returned stop function is invoked.
|
|
143
|
+
*
|
|
144
|
+
* Useful for broadcast messages (COHORT_ADVERT) on relays that don't
|
|
145
|
+
* backfill historical events to late subscribers: republishing gives late
|
|
146
|
+
* joiners a window to discover the message without requiring protocol
|
|
147
|
+
* changes. Relay rate-limit / publish failures inside the interval are
|
|
148
|
+
* caught and logged rather than propagated — the caller should stop the
|
|
149
|
+
* repeater once the protocol condition is satisfied.
|
|
150
|
+
*/
|
|
151
|
+
publishRepeating(message: BaseMessage, sender: Did, intervalMs: number, recipient?: Did): () => void;
|
|
54
152
|
}
|
|
55
153
|
//# sourceMappingURL=nostr.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nostr.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/nostr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"nostr.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/nostr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,UAKhC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,uFAAuF;AACvF,eAAO,MAAM,6BAA6B,QAAgB,CAAC;AAU3D;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAe,YAAW,SAAS;;IAC9C,IAAI,EAAE,MAAM,CAAW;IAEvB,IAAI,CAAC,EAAE,UAAU,CAAC;gBAQN,MAAM,CAAC,EAAE,oBAAoB;IAMzC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IAUtD;;;;;;;;OAQG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAYlC;;;;;;;OAOG;IACH,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAMrE;;;;;OAKG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,GAAG,IAAI;IAY5D;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI9C;;;;;;;;;OASG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;IAW5F;;;;;;;;OAQG;IACH,KAAK,IAAI,cAAc;IAsCvB;;;;;;;;;;;OAWG;IACG,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAmF7E;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,GAAG,MAAM,IAAI;CAwNrG"}
|
|
@@ -31,7 +31,32 @@ export interface Transport {
|
|
|
31
31
|
getPeerPk(did: string): Uint8Array | undefined;
|
|
32
32
|
/** Register a message handler scoped to a specific actor. */
|
|
33
33
|
registerMessageHandler(actorDid: string, messageType: string, handler: MessageHandler): void;
|
|
34
|
+
/** Remove a previously-registered handler. No-op if not registered. */
|
|
35
|
+
unregisterMessageHandler(actorDid: string, messageType: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Detach an actor: unregister all its handlers, drop its keys, and close any
|
|
38
|
+
* transport-level subscriptions created for it. No-op if the actor is not
|
|
39
|
+
* registered.
|
|
40
|
+
*/
|
|
41
|
+
unregisterActor(did: string): void;
|
|
34
42
|
/** Send a message. The transport looks up sender to resolve signing keys. */
|
|
35
43
|
sendMessage(message: BaseMessage, sender: string, recipient?: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Publish the message once immediately and then repeat it on a fixed
|
|
46
|
+
* interval. Returns a stop function the caller MUST invoke when the repeat
|
|
47
|
+
* is no longer needed (e.g. once the protocol state that required the
|
|
48
|
+
* message is satisfied).
|
|
49
|
+
*
|
|
50
|
+
* Useful for broadcasts on transports that don't reliably backfill
|
|
51
|
+
* historical events to late subscribers (many Nostr relays) — republishing
|
|
52
|
+
* gives late joiners a window in which to discover the message. The first
|
|
53
|
+
* publish is synchronous-ish (fired before the method returns).
|
|
54
|
+
*
|
|
55
|
+
* Callers specify `recipient` only for directed messages; for broadcasts
|
|
56
|
+
* it is omitted.
|
|
57
|
+
*
|
|
58
|
+
* @returns A stop function. Idempotent — safe to call more than once.
|
|
59
|
+
*/
|
|
60
|
+
publishRepeating(message: BaseMessage, sender: string, intervalMs: number, recipient?: string): () => void;
|
|
36
61
|
}
|
|
37
62
|
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;AACpD,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAEtE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IAEb,sEAAsE;IACtE,KAAK,IAAI,IAAI,CAAC;IAEd,sEAAsE;IACtE,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAEvD,uEAAuE;IACvE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAEhD,4EAA4E;IAC5E,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,GAAG,IAAI,CAAC;IAE7D,yDAAyD;IACzD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAE/C,6DAA6D;IAC7D,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAE7F,6EAA6E;IAC7E,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;AACpD,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAEtE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IAEb,sEAAsE;IACtE,KAAK,IAAI,IAAI,CAAC;IAEd,sEAAsE;IACtE,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAEvD,uEAAuE;IACvE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAEhD,4EAA4E;IAC5E,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,GAAG,IAAI,CAAC;IAE7D,yDAAyD;IACzD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAE/C,6DAA6D;IAC7D,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAE7F,uEAAuE;IACvE,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtE;;;;OAIG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,6EAA6E;IAC7E,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErF;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CACd,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,IAAI,CAAC;CACf"}
|
|
@@ -1,17 +1,68 @@
|
|
|
1
|
-
import type { BitcoinConnection } from '@did-btcr2/bitcoin';
|
|
1
|
+
import type { AddressUtxo, BitcoinConnection, BTCNetwork } from '@did-btcr2/bitcoin';
|
|
2
2
|
import type { KeyBytes } from '@did-btcr2/common';
|
|
3
3
|
import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
|
|
4
|
+
import { Transaction } from '@scure/btc-signer';
|
|
4
5
|
import type { BeaconProcessResult } from '../resolver.js';
|
|
5
6
|
import type { SidecarData } from '../types.js';
|
|
6
7
|
import type { FeeEstimator } from './fee-estimator.js';
|
|
7
8
|
import type { BeaconService, BeaconSignal } from './interfaces.js';
|
|
8
9
|
/**
|
|
9
|
-
* Options accepted by {@link Beacon.buildSignAndBroadcast}.
|
|
10
|
+
* Options accepted by {@link Beacon.buildSignAndBroadcast} and related helpers.
|
|
10
11
|
*/
|
|
11
12
|
export interface BroadcastOptions {
|
|
12
13
|
/** Fee estimator for computing the transaction fee. Defaults to {@link DEFAULT_FEE_ESTIMATOR}. */
|
|
13
14
|
feeEstimator?: FeeEstimator;
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Unsigned beacon transaction + the prev-output metadata needed for downstream
|
|
18
|
+
* signing (single-party ECDSA or multi-party MuSig2 Taproot).
|
|
19
|
+
*/
|
|
20
|
+
export interface BeaconTxPlan {
|
|
21
|
+
/** The unsigned scure @scure/btc-signer Transaction. */
|
|
22
|
+
tx: Transaction;
|
|
23
|
+
/** Scripts of the consumed previous outputs (needed for Taproot sighash). */
|
|
24
|
+
prevOutScripts: Uint8Array[];
|
|
25
|
+
/** Amounts (sats) of the consumed previous outputs. */
|
|
26
|
+
prevOutValues: bigint[];
|
|
27
|
+
/** Address change was sent back to (same as the beacon address). */
|
|
28
|
+
beaconAddress: string;
|
|
29
|
+
/** The UTXO this tx consumes. */
|
|
30
|
+
utxo: AddressUtxo;
|
|
31
|
+
/** The fee (sats) already deducted from the change output. */
|
|
32
|
+
feeSats: bigint;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build an OP_RETURN script carrying a 32-byte beacon signal.
|
|
36
|
+
* Exported as a utility so callers building txs outside Beacon (e.g., the aggregation
|
|
37
|
+
* `onProvideTxData` callback) can produce identical output.
|
|
38
|
+
*/
|
|
39
|
+
export declare function opReturnScript(signalBytes: Uint8Array): Uint8Array;
|
|
40
|
+
/**
|
|
41
|
+
* Build an aggregation beacon transaction (P2TR key-path spend) ready for MuSig2 signing.
|
|
42
|
+
* Returns the unsigned Transaction + prev-output metadata that an aggregation service's
|
|
43
|
+
* signing session consumes (via {@link SigningTxData}).
|
|
44
|
+
*
|
|
45
|
+
* This is the reusable counterpart to {@link Beacon.buildSignAndBroadcast}'s internal
|
|
46
|
+
* construction step — the aggregation path must produce an unsigned tx because the
|
|
47
|
+
* signature comes from a MuSig2 round, not a local secret key.
|
|
48
|
+
*
|
|
49
|
+
* @param opts Parameters including the cohort's aggregate internal pubkey.
|
|
50
|
+
* @returns A {@link BeaconTxPlan} with the unsigned tx and sighash inputs.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildAggregationBeaconTx(opts: {
|
|
53
|
+
/** The beacon (cohort) address where UTXOs live and change returns to. */
|
|
54
|
+
beaconAddress: string;
|
|
55
|
+
/** The cohort's MuSig2-aggregated x-only internal pubkey (32 bytes). */
|
|
56
|
+
internalPubkey: Uint8Array;
|
|
57
|
+
/** 32-byte beacon signal embedded in the OP_RETURN output. */
|
|
58
|
+
signalBytes: Uint8Array;
|
|
59
|
+
/** Bitcoin REST connection for UTXO / prev-tx lookup. */
|
|
60
|
+
bitcoin: BitcoinConnection;
|
|
61
|
+
/** Network params used to derive the P2TR witnessUtxo script. */
|
|
62
|
+
network: BTCNetwork;
|
|
63
|
+
/** Optional fee estimator (defaults to 5 sat/vB). */
|
|
64
|
+
feeEstimator?: FeeEstimator;
|
|
65
|
+
}): Promise<BeaconTxPlan>;
|
|
15
66
|
/**
|
|
16
67
|
* Abstract base class for all BTCR2 Beacon types.
|
|
17
68
|
* A Beacon is a service listed in a BTCR2 DID document that informs resolvers
|
|
@@ -28,6 +79,7 @@ export interface BroadcastOptions {
|
|
|
28
79
|
* @type {Beacon}
|
|
29
80
|
*/
|
|
30
81
|
export declare abstract class Beacon {
|
|
82
|
+
#private;
|
|
31
83
|
/**
|
|
32
84
|
* The Beacon service configuration parsed from the DID Document.
|
|
33
85
|
*/
|
|
@@ -56,30 +108,45 @@ export declare abstract class Beacon {
|
|
|
56
108
|
*/
|
|
57
109
|
abstract broadcastSignal(signedUpdate: SignedBTCR2Update, secretKey: KeyBytes, bitcoin: BitcoinConnection, options?: BroadcastOptions): Promise<SignedBTCR2Update>;
|
|
58
110
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* Steps:
|
|
62
|
-
* 1. Parse the beacon's `serviceEndpoint` (stripping `bitcoin:` prefix) into a Bitcoin address.
|
|
63
|
-
* 2. Query the address for unconfirmed/confirmed UTXOs.
|
|
64
|
-
* 3. Select the most recent confirmed UTXO.
|
|
65
|
-
* 4. Fetch the previous transaction hex for `nonWitnessUtxo`.
|
|
66
|
-
* 5. Build a PSBT: input (UTXO) → change output + OP_RETURN(signalBytes).
|
|
67
|
-
* 6. Compute the fee via the supplied (or default) {@link FeeEstimator} against the tx vsize.
|
|
68
|
-
* 7. Sign input 0 with an ECDSA signer derived from `secretKey`.
|
|
69
|
-
* 8. Finalize, extract, and broadcast via the REST transaction endpoint.
|
|
111
|
+
* Build + sign + broadcast a single-party beacon signal transaction (P2WPKH spend).
|
|
70
112
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
113
|
+
* Composed from the three extracted phases ({@link buildSinglePartyTx},
|
|
114
|
+
* {@link signSinglePartyTx}, {@link broadcastRawTx}) so each piece can be exercised
|
|
115
|
+
* in isolation. Aggregation beacons use {@link buildAggregationBeaconTx} instead —
|
|
116
|
+
* the multi-party path can't share the signing phase, but the tx-construction
|
|
117
|
+
* plumbing (UTXO fetch + OP_RETURN output + change output) is shared.
|
|
75
118
|
*
|
|
76
119
|
* @param signalBytes 32-byte payload to embed in OP_RETURN.
|
|
77
120
|
* @param secretKey Secret key used to sign the spending input.
|
|
78
121
|
* @param bitcoin Bitcoin network connection.
|
|
79
122
|
* @param options Broadcast options (fee estimator, etc.).
|
|
80
123
|
* @returns The txid of the broadcast transaction.
|
|
81
|
-
* @throws {BeaconError} if the address is unfunded
|
|
124
|
+
* @throws {BeaconError} if the address is unfunded, no UTXO is available, or fee exceeds value.
|
|
82
125
|
*/
|
|
83
126
|
protected buildSignAndBroadcast(signalBytes: Uint8Array, secretKey: KeyBytes, bitcoin: BitcoinConnection, options?: BroadcastOptions): Promise<string>;
|
|
127
|
+
/**
|
|
128
|
+
* Build an unsigned P2WPKH single-party beacon tx + probe-sign to determine vsize,
|
|
129
|
+
* then rebuild with the real fee. Returns the tx and prev-output metadata.
|
|
130
|
+
*
|
|
131
|
+
* The secret key is required here (not just in `signSinglePartyTx`) because the
|
|
132
|
+
* two-pass fee estimation requires an actual signature to measure vsize accurately.
|
|
133
|
+
*/
|
|
134
|
+
protected buildSinglePartyTx(opts: {
|
|
135
|
+
signalBytes: Uint8Array;
|
|
136
|
+
beaconAddress: string;
|
|
137
|
+
utxo: AddressUtxo;
|
|
138
|
+
prevTxBytes: Uint8Array;
|
|
139
|
+
secretKey: KeyBytes;
|
|
140
|
+
bitcoin: BitcoinConnection;
|
|
141
|
+
feeEstimator: FeeEstimator;
|
|
142
|
+
}): Promise<BeaconTxPlan>;
|
|
143
|
+
/**
|
|
144
|
+
* Sign + finalize the unsigned single-party tx and return its raw hex.
|
|
145
|
+
*/
|
|
146
|
+
protected signSinglePartyTx(tx: Transaction, secretKey: KeyBytes): string;
|
|
147
|
+
/**
|
|
148
|
+
* Broadcast raw transaction hex via the Bitcoin REST endpoint. Returns the txid.
|
|
149
|
+
*/
|
|
150
|
+
protected broadcastRawTx(bitcoin: BitcoinConnection, rawHex: string): Promise<string>;
|
|
84
151
|
}
|
|
85
152
|
//# sourceMappingURL=beacon.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beacon.d.ts","sourceRoot":"","sources":["../../../../src/core/beacon/beacon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"beacon.d.ts","sourceRoot":"","sources":["../../../../src/core/beacon/beacon.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { BTCNetwork } from '@did-btcr2/bitcoin';
|
|
1
2
|
import type { KeyBytes, Maybe } from '@did-btcr2/common';
|
|
2
|
-
import type { networks } from 'bitcoinjs-lib';
|
|
3
3
|
import type { DidDocument } from '../../utils/did-document.js';
|
|
4
4
|
import type { BeaconService } from './interfaces.js';
|
|
5
5
|
/**
|
|
@@ -53,7 +53,7 @@ export declare class BeaconUtils {
|
|
|
53
53
|
static generateBeaconServices({ id, publicKey, network, beaconType }: {
|
|
54
54
|
id: string;
|
|
55
55
|
publicKey: KeyBytes;
|
|
56
|
-
network:
|
|
56
|
+
network: BTCNetwork;
|
|
57
57
|
beaconType: string;
|
|
58
58
|
}): Array<BeaconService>;
|
|
59
59
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/core/beacon/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/core/beacon/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAIxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD;;;;GAIG;AACH,qBAAa,WAAW;IACtB;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAO/C;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,OAAO;IAc1D;;;;;OAKG;IACH,MAAM,CAAC,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE;IAKnE;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC;IAiBlF;;;;;;;OAOG;IACH,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa;IA2BpH;;;;;OAKG;IACH,MAAM,CAAC,sBAAsB,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE;QACpE,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,QAAQ,CAAC;QACpB,OAAO,EAAE,UAAU,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,KAAK,CAAC,aAAa,CAAC;IAoCxB;;;;OAIG;IACH,MAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa;IAIvE;;;;OAIG;IACH,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC;IAQtF;;;;OAIG;IACH,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,EAAE;CAG/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"did-btcr2.d.ts","sourceRoot":"","sources":["../../src/did-btcr2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAS3C,OAAO,KAAK,EACV,SAAS,EAAC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"did-btcr2.d.ts","sourceRoot":"","sources":["../../src/did-btcr2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAS3C,OAAO,KAAK,EACV,SAAS,EAAC,MAAM,YAAY,CAAC;AAQ/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEvF,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;AAED;;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,MAAM,CAAC,EACZ,cAAc,EACd,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,QAAQ,GACT,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;KAClB,GAAG,OAAO;IA2DX;;;;;;;;;OASG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,EAAG,QAAQ,CAAC,EAAE,MAAM,GAAG,qBAAqB;CA0BlG"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from './core/aggregation/cohort.js';
|
|
|
4
4
|
export * from './core/aggregation/signing-session.js';
|
|
5
5
|
export * from './core/aggregation/phases.js';
|
|
6
6
|
export * from './core/aggregation/errors.js';
|
|
7
|
+
export * from './core/aggregation/beacon-strategy.js';
|
|
8
|
+
export * from './core/aggregation/logger.js';
|
|
7
9
|
export * from './core/aggregation/messages/index.js';
|
|
8
10
|
export * from './core/aggregation/transport/index.js';
|
|
9
11
|
export * from './core/aggregation/runner/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAGxC,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAGvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AAGxC,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.29.0",
|
|
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",
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"bitcoin"
|
|
65
65
|
],
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@bitcoinerlab/secp256k1": "^1.2.0",
|
|
68
67
|
"@helia/strings": "^4.1.0",
|
|
69
68
|
"@noble/curves": "^1.9.7",
|
|
70
69
|
"@noble/hashes": "^1.8.0",
|
|
@@ -76,17 +75,16 @@
|
|
|
76
75
|
"@web5/common": "^1.1.0",
|
|
77
76
|
"@web5/crypto": "^1.0.6",
|
|
78
77
|
"@web5/dids": "^1.2.0",
|
|
79
|
-
"bitcoinjs-lib": "7.0.0-rc.0",
|
|
80
78
|
"canonicalize": "^2.1.0",
|
|
81
79
|
"dotenv": "^16.6.1",
|
|
82
80
|
"helia": "^5.5.1",
|
|
83
81
|
"multiformats": "^13.4.2",
|
|
84
82
|
"nostr-tools": "^2.23.3",
|
|
85
|
-
"@did-btcr2/bitcoin": "^0.5.3",
|
|
86
|
-
"@did-btcr2/cryptosuite": "^6.0.6",
|
|
87
83
|
"@did-btcr2/smt": "^0.2.4",
|
|
88
|
-
"@did-btcr2/
|
|
89
|
-
"@did-btcr2/
|
|
84
|
+
"@did-btcr2/cryptosuite": "^6.0.6",
|
|
85
|
+
"@did-btcr2/bitcoin": "^0.6.0",
|
|
86
|
+
"@did-btcr2/common": "^9.0.0",
|
|
87
|
+
"@did-btcr2/keypair": "^0.11.4"
|
|
90
88
|
},
|
|
91
89
|
"devDependencies": {
|
|
92
90
|
"@eslint/js": "^9.39.4",
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { canonicalize } from '@did-btcr2/common';
|
|
2
|
+
import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
|
|
3
|
+
import type { SerializedSMTProof } from '@did-btcr2/smt';
|
|
4
|
+
import { blockHash, didToIndex, hashToHex, hexToHash, verifySerializedProof } from '@did-btcr2/smt';
|
|
5
|
+
import type { AggregationCohort } from './cohort.js';
|
|
6
|
+
import type { BaseBody } from './messages/base.js';
|
|
7
|
+
|
|
8
|
+
/** Validation result returned to the participant for a distribute-data message. */
|
|
9
|
+
export interface BeaconValidationResult {
|
|
10
|
+
matches: boolean;
|
|
11
|
+
casAnnouncement?: Record<string, string>;
|
|
12
|
+
smtProof?: SerializedSMTProof;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Per-participant body attached to DISTRIBUTE_AGGREGATED_DATA by the service. */
|
|
16
|
+
export interface BeaconDistributePayload {
|
|
17
|
+
casAnnouncement?: Record<string, string>;
|
|
18
|
+
smtProof?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Pluggable strategy for beacon-type-specific aggregation, distribution, and
|
|
23
|
+
* participant-side validation. Lets new beacon types be added without
|
|
24
|
+
* modifying the service or participant state machines: register a new strategy
|
|
25
|
+
* via {@link registerBeaconStrategy}.
|
|
26
|
+
*/
|
|
27
|
+
export interface AggregateBeaconStrategy {
|
|
28
|
+
/** String constant used as `beaconType` on CohortConfig / BaseMessage bodies. */
|
|
29
|
+
readonly type: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Service: build the aggregated data on the cohort after all updates are
|
|
33
|
+
* collected. Implementation should mutate the cohort (set signalBytes,
|
|
34
|
+
* casAnnouncement, smtProofs, etc.).
|
|
35
|
+
*/
|
|
36
|
+
buildAggregatedData(cohort: AggregationCohort): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Service: produce the body fields to attach to DISTRIBUTE_AGGREGATED_DATA
|
|
40
|
+
* for a specific participant. Called once per cohort member.
|
|
41
|
+
*/
|
|
42
|
+
getDistributePayload(cohort: AggregationCohort, participantDid: string): BeaconDistributePayload;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Participant: verify the aggregated data they received reflects their own
|
|
46
|
+
* submitted update. Pure function — returns matches + sidecar fields for
|
|
47
|
+
* the caller to store.
|
|
48
|
+
*/
|
|
49
|
+
validateParticipantView(params: {
|
|
50
|
+
participantDid: string;
|
|
51
|
+
submittedUpdate: SignedBTCR2Update;
|
|
52
|
+
expectedHash: string;
|
|
53
|
+
body: BaseBody;
|
|
54
|
+
}): BeaconValidationResult;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const CAS_STRATEGY: AggregateBeaconStrategy = {
|
|
58
|
+
type : 'CASBeacon',
|
|
59
|
+
|
|
60
|
+
buildAggregatedData(cohort) {
|
|
61
|
+
cohort.buildCASAnnouncement();
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
getDistributePayload(cohort) {
|
|
65
|
+
return { casAnnouncement: cohort.casAnnouncement };
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
validateParticipantView({ participantDid, expectedHash, body }) {
|
|
69
|
+
const casAnnouncement = body.casAnnouncement;
|
|
70
|
+
if(!casAnnouncement) return { matches: false };
|
|
71
|
+
return {
|
|
72
|
+
matches : casAnnouncement[participantDid] === expectedHash,
|
|
73
|
+
casAnnouncement,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const SMT_STRATEGY: AggregateBeaconStrategy = {
|
|
79
|
+
type : 'SMTBeacon',
|
|
80
|
+
|
|
81
|
+
buildAggregatedData(cohort) {
|
|
82
|
+
cohort.buildSMTTree();
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
getDistributePayload(cohort, participantDid) {
|
|
86
|
+
const proof = cohort.smtProofs?.get(participantDid);
|
|
87
|
+
return { smtProof: proof as unknown as Record<string, unknown> | undefined };
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
validateParticipantView({ participantDid, submittedUpdate, body }) {
|
|
91
|
+
const smtProof = body.smtProof as unknown as SerializedSMTProof | undefined;
|
|
92
|
+
if(!smtProof?.updateId || !smtProof?.nonce) return { matches: false };
|
|
93
|
+
// Verify updateId matches the canonicalized update hash
|
|
94
|
+
const canonicalBytes = new TextEncoder().encode(canonicalize(submittedUpdate as unknown as Record<string, unknown>));
|
|
95
|
+
const expectedUpdateId = hashToHex(blockHash(canonicalBytes));
|
|
96
|
+
if(smtProof.updateId !== expectedUpdateId) {
|
|
97
|
+
return { matches: false, smtProof };
|
|
98
|
+
}
|
|
99
|
+
// Verify Merkle inclusion
|
|
100
|
+
const index = didToIndex(participantDid);
|
|
101
|
+
const candidateHash = blockHash(blockHash(hexToHash(smtProof.nonce)), hexToHash(smtProof.updateId));
|
|
102
|
+
return {
|
|
103
|
+
matches : verifySerializedProof(smtProof, index, candidateHash),
|
|
104
|
+
smtProof,
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** Registered strategies keyed by `beaconType` string. */
|
|
110
|
+
const STRATEGIES: Map<string, AggregateBeaconStrategy> = new Map([
|
|
111
|
+
[CAS_STRATEGY.type, CAS_STRATEGY],
|
|
112
|
+
[SMT_STRATEGY.type, SMT_STRATEGY],
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
/** Register a custom beacon strategy. Overwrites any existing entry with the same type. */
|
|
116
|
+
export function registerBeaconStrategy(strategy: AggregateBeaconStrategy): void {
|
|
117
|
+
STRATEGIES.set(strategy.type, strategy);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Look up a registered beacon strategy by type, or undefined if not registered. */
|
|
121
|
+
export function getBeaconStrategy(type: string): AggregateBeaconStrategy | undefined {
|
|
122
|
+
return STRATEGIES.get(type);
|
|
123
|
+
}
|
|
@@ -2,9 +2,10 @@ import { canonicalHash, canonicalize, hash } from '@did-btcr2/common';
|
|
|
2
2
|
import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
|
|
3
3
|
import type { SerializedSMTProof, TreeEntry } from '@did-btcr2/smt';
|
|
4
4
|
import { BTCR2MerkleTree } from '@did-btcr2/smt';
|
|
5
|
+
import { schnorr } from '@noble/curves/secp256k1.js';
|
|
5
6
|
import { hexToBytes, randomBytes } from '@noble/hashes/utils';
|
|
7
|
+
import { p2tr } from '@scure/btc-signer';
|
|
6
8
|
import { keyAggExport, keyAggregate, sortKeys } from '@scure/btc-signer/musig2';
|
|
7
|
-
import { crypto as btcCrypto, payments } from 'bitcoinjs-lib';
|
|
8
9
|
import type { CASAnnouncement } from '../types.js';
|
|
9
10
|
import { AggregationCohortError } from './errors.js';
|
|
10
11
|
|
|
@@ -48,11 +49,23 @@ export class AggregationCohort {
|
|
|
48
49
|
/** List of participant DIDs that have been accepted into the cohort. */
|
|
49
50
|
participants: Array<string> = [];
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Mapping from participant DID → their compressed secp256k1 public key.
|
|
54
|
+
* Distinct from {@link cohortKeys} (which is sorted per BIP-327) — this lets
|
|
55
|
+
* callers look up a participant's key without knowing their position in the
|
|
56
|
+
* sorted array. Populated by the service at `acceptParticipant` time.
|
|
57
|
+
*/
|
|
58
|
+
participantKeys: Map<string, Uint8Array> = new Map();
|
|
59
|
+
|
|
51
60
|
/** Sorted list of cohort participants' compressed public keys. */
|
|
52
61
|
#cohortKeys: Array<Uint8Array> = [];
|
|
53
62
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
63
|
+
/**
|
|
64
|
+
* BIP-341 TapTweak — `taggedHash("TapTweak", internalPubkey)` for a key-path-only
|
|
65
|
+
* Taproot output. Despite prior naming, this is NOT a Merkle root: key-path-only
|
|
66
|
+
* spends have no script tree.
|
|
67
|
+
*/
|
|
68
|
+
tapTweak: Uint8Array = new Uint8Array();
|
|
56
69
|
|
|
57
70
|
/** The n-of-n MuSig2 Taproot beacon address. */
|
|
58
71
|
beaconAddress: string = '';
|
|
@@ -94,7 +107,7 @@ export class AggregationCohort {
|
|
|
94
107
|
|
|
95
108
|
/**
|
|
96
109
|
* Computes the n-of-n MuSig2 Taproot beacon address from cohort keys.
|
|
97
|
-
* Sets `
|
|
110
|
+
* Sets `tapTweak` to the BIP-341 key-path-only tweak.
|
|
98
111
|
*/
|
|
99
112
|
public computeBeaconAddress(): string {
|
|
100
113
|
if(this.#cohortKeys.length === 0) {
|
|
@@ -105,11 +118,11 @@ export class AggregationCohort {
|
|
|
105
118
|
}
|
|
106
119
|
const keyAggContext = keyAggregate(this.#cohortKeys);
|
|
107
120
|
const aggPubkey = keyAggExport(keyAggContext);
|
|
108
|
-
const payment =
|
|
121
|
+
const payment = p2tr(aggPubkey);
|
|
109
122
|
|
|
110
|
-
// BIP-341: key-path-only P2TR has no script tree
|
|
111
|
-
//
|
|
112
|
-
this.
|
|
123
|
+
// BIP-341: key-path-only P2TR has no script tree. Compute the tweak:
|
|
124
|
+
// taggedHash("TapTweak", internalPubkey).
|
|
125
|
+
this.tapTweak = schnorr.utils.taggedHash('TapTweak', aggPubkey);
|
|
113
126
|
|
|
114
127
|
if(!payment.address) {
|
|
115
128
|
throw new AggregationCohortError(
|
|
@@ -147,6 +160,19 @@ export class AggregationCohort {
|
|
|
147
160
|
}
|
|
148
161
|
}
|
|
149
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Returns the position of a participant's public key in the sorted
|
|
165
|
+
* {@link cohortKeys} array, or -1 if the participant is not in the cohort.
|
|
166
|
+
* Required by MuSig2 partial-sig verification which indexes by signer position.
|
|
167
|
+
*/
|
|
168
|
+
public indexOfParticipant(did: string): number {
|
|
169
|
+
const pk = this.participantKeys.get(did);
|
|
170
|
+
if(!pk) return -1;
|
|
171
|
+
return this.#cohortKeys.findIndex(k =>
|
|
172
|
+
k.length === pk.length && k.every((b, i) => b === pk[i])
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
150
176
|
public addUpdate(participantDid: string, signedUpdate: SignedBTCR2Update): void {
|
|
151
177
|
if(!this.participants.includes(participantDid)) {
|
|
152
178
|
throw new AggregationCohortError(
|