@did-btcr2/method 0.13.1
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/LICENSE +373 -0
- package/README.md +7 -0
- package/dist/browser.js +2364 -0
- package/dist/browser.js.map +7 -0
- package/dist/browser.mjs +2364 -0
- package/dist/browser.mjs.map +7 -0
- package/dist/cjs/bitcoin/constants.js +20 -0
- package/dist/cjs/bitcoin/constants.js.map +1 -0
- package/dist/cjs/bitcoin/errors.js +11 -0
- package/dist/cjs/bitcoin/errors.js.map +1 -0
- package/dist/cjs/bitcoin/index.js +95 -0
- package/dist/cjs/bitcoin/index.js.map +1 -0
- package/dist/cjs/bitcoin/interface.js +2 -0
- package/dist/cjs/bitcoin/interface.js.map +1 -0
- package/dist/cjs/bitcoin/network.js +17 -0
- package/dist/cjs/bitcoin/network.js.map +1 -0
- package/dist/cjs/bitcoin/rest-client.js +289 -0
- package/dist/cjs/bitcoin/rest-client.js.map +1 -0
- package/dist/cjs/bitcoin/rpc-client.js +722 -0
- package/dist/cjs/bitcoin/rpc-client.js.map +1 -0
- package/dist/cjs/bitcoin/taproot.js +219 -0
- package/dist/cjs/bitcoin/taproot.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/coordinator.js +120 -0
- package/dist/cjs/btcr2/beacon/aggregation/coordinator.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/advert.js +24 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/advert.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/base.js +37 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/base.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/cohort-set.js +25 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/cohort-set.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/keygen.js +8 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/keygen.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/opt-in.js +23 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/opt-in.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/sign.js +7 -0
- package/dist/cjs/btcr2/beacon/aggregation/messages/sign.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/models/cohort/index.js +92 -0
- package/dist/cjs/btcr2/beacon/aggregation/models/cohort/index.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/models/cohort/status.js +8 -0
- package/dist/cjs/btcr2/beacon/aggregation/models/cohort/status.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/participant.js +2 -0
- package/dist/cjs/btcr2/beacon/aggregation/participant.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/protocol/nostr.js +57 -0
- package/dist/cjs/btcr2/beacon/aggregation/protocol/nostr.js.map +1 -0
- package/dist/cjs/btcr2/beacon/aggregation/protocol/service.js +2 -0
- package/dist/cjs/btcr2/beacon/aggregation/protocol/service.js.map +1 -0
- package/dist/cjs/btcr2/beacon/cid-aggregate.js +116 -0
- package/dist/cjs/btcr2/beacon/cid-aggregate.js.map +1 -0
- package/dist/cjs/btcr2/beacon/factory.js +30 -0
- package/dist/cjs/btcr2/beacon/factory.js.map +1 -0
- package/dist/cjs/btcr2/beacon/singleton.js +220 -0
- package/dist/cjs/btcr2/beacon/singleton.js.map +1 -0
- package/dist/cjs/btcr2/beacon/smt-aggregate.js +126 -0
- package/dist/cjs/btcr2/beacon/smt-aggregate.js.map +1 -0
- package/dist/cjs/btcr2/crud/create.js +102 -0
- package/dist/cjs/btcr2/crud/create.js.map +1 -0
- package/dist/cjs/btcr2/crud/deactivate.js +14 -0
- package/dist/cjs/btcr2/crud/deactivate.js.map +1 -0
- package/dist/cjs/btcr2/crud/read.js +686 -0
- package/dist/cjs/btcr2/crud/read.js.map +1 -0
- package/dist/cjs/btcr2/crud/update.js +195 -0
- package/dist/cjs/btcr2/crud/update.js.map +1 -0
- package/dist/cjs/btcr2/key-manager/index.js +290 -0
- package/dist/cjs/btcr2/key-manager/index.js.map +1 -0
- package/dist/cjs/btcr2/key-manager/interface.js +2 -0
- package/dist/cjs/btcr2/key-manager/interface.js.map +1 -0
- package/dist/cjs/did-btcr2.js +222 -0
- package/dist/cjs/did-btcr2.js.map +1 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces/beacon.js +41 -0
- package/dist/cjs/interfaces/beacon.js.map +1 -0
- package/dist/cjs/interfaces/crud.js +2 -0
- package/dist/cjs/interfaces/crud.js.map +1 -0
- package/dist/cjs/interfaces/ibeacon.js +2 -0
- package/dist/cjs/interfaces/ibeacon.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/bitcoin.js +62 -0
- package/dist/cjs/types/bitcoin.js.map +1 -0
- package/dist/cjs/types/crud.js +2 -0
- package/dist/cjs/types/crud.js.map +1 -0
- package/dist/cjs/utils/appendix.js +221 -0
- package/dist/cjs/utils/appendix.js.map +1 -0
- package/dist/cjs/utils/beacons.js +206 -0
- package/dist/cjs/utils/beacons.js.map +1 -0
- package/dist/cjs/utils/did-document-builder.js +61 -0
- package/dist/cjs/utils/did-document-builder.js.map +1 -0
- package/dist/cjs/utils/did-document.js +380 -0
- package/dist/cjs/utils/did-document.js.map +1 -0
- package/dist/cjs/utils/general.js +195 -0
- package/dist/cjs/utils/general.js.map +1 -0
- package/dist/cjs/utils/identifier.js +238 -0
- package/dist/cjs/utils/identifier.js.map +1 -0
- package/dist/esm/bitcoin/constants.js +20 -0
- package/dist/esm/bitcoin/constants.js.map +1 -0
- package/dist/esm/bitcoin/errors.js +11 -0
- package/dist/esm/bitcoin/errors.js.map +1 -0
- package/dist/esm/bitcoin/index.js +95 -0
- package/dist/esm/bitcoin/index.js.map +1 -0
- package/dist/esm/bitcoin/interface.js +2 -0
- package/dist/esm/bitcoin/interface.js.map +1 -0
- package/dist/esm/bitcoin/network.js +17 -0
- package/dist/esm/bitcoin/network.js.map +1 -0
- package/dist/esm/bitcoin/rest-client.js +289 -0
- package/dist/esm/bitcoin/rest-client.js.map +1 -0
- package/dist/esm/bitcoin/rpc-client.js +722 -0
- package/dist/esm/bitcoin/rpc-client.js.map +1 -0
- package/dist/esm/bitcoin/taproot.js +219 -0
- package/dist/esm/bitcoin/taproot.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/coordinator.js +120 -0
- package/dist/esm/btcr2/beacon/aggregation/coordinator.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/advert.js +24 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/advert.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/base.js +37 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/base.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/cohort-set.js +25 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/cohort-set.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/keygen.js +8 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/keygen.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/opt-in.js +23 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/opt-in.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/sign.js +7 -0
- package/dist/esm/btcr2/beacon/aggregation/messages/sign.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/models/cohort/index.js +92 -0
- package/dist/esm/btcr2/beacon/aggregation/models/cohort/index.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/models/cohort/status.js +8 -0
- package/dist/esm/btcr2/beacon/aggregation/models/cohort/status.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/participant.js +2 -0
- package/dist/esm/btcr2/beacon/aggregation/participant.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/protocol/nostr.js +57 -0
- package/dist/esm/btcr2/beacon/aggregation/protocol/nostr.js.map +1 -0
- package/dist/esm/btcr2/beacon/aggregation/protocol/service.js +2 -0
- package/dist/esm/btcr2/beacon/aggregation/protocol/service.js.map +1 -0
- package/dist/esm/btcr2/beacon/cid-aggregate.js +116 -0
- package/dist/esm/btcr2/beacon/cid-aggregate.js.map +1 -0
- package/dist/esm/btcr2/beacon/factory.js +30 -0
- package/dist/esm/btcr2/beacon/factory.js.map +1 -0
- package/dist/esm/btcr2/beacon/singleton.js +220 -0
- package/dist/esm/btcr2/beacon/singleton.js.map +1 -0
- package/dist/esm/btcr2/beacon/smt-aggregate.js +126 -0
- package/dist/esm/btcr2/beacon/smt-aggregate.js.map +1 -0
- package/dist/esm/btcr2/crud/create.js +102 -0
- package/dist/esm/btcr2/crud/create.js.map +1 -0
- package/dist/esm/btcr2/crud/deactivate.js +14 -0
- package/dist/esm/btcr2/crud/deactivate.js.map +1 -0
- package/dist/esm/btcr2/crud/read.js +686 -0
- package/dist/esm/btcr2/crud/read.js.map +1 -0
- package/dist/esm/btcr2/crud/update.js +195 -0
- package/dist/esm/btcr2/crud/update.js.map +1 -0
- package/dist/esm/btcr2/key-manager/index.js +290 -0
- package/dist/esm/btcr2/key-manager/index.js.map +1 -0
- package/dist/esm/btcr2/key-manager/interface.js +2 -0
- package/dist/esm/btcr2/key-manager/interface.js.map +1 -0
- package/dist/esm/did-btcr2.js +222 -0
- package/dist/esm/did-btcr2.js.map +1 -0
- package/dist/esm/index.js +27 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interfaces/beacon.js +41 -0
- package/dist/esm/interfaces/beacon.js.map +1 -0
- package/dist/esm/interfaces/crud.js +2 -0
- package/dist/esm/interfaces/crud.js.map +1 -0
- package/dist/esm/interfaces/ibeacon.js +2 -0
- package/dist/esm/interfaces/ibeacon.js.map +1 -0
- package/dist/esm/types/bitcoin.js +62 -0
- package/dist/esm/types/bitcoin.js.map +1 -0
- package/dist/esm/types/crud.js +2 -0
- package/dist/esm/types/crud.js.map +1 -0
- package/dist/esm/utils/appendix.js +221 -0
- package/dist/esm/utils/appendix.js.map +1 -0
- package/dist/esm/utils/beacons.js +206 -0
- package/dist/esm/utils/beacons.js.map +1 -0
- package/dist/esm/utils/did-document-builder.js +61 -0
- package/dist/esm/utils/did-document-builder.js.map +1 -0
- package/dist/esm/utils/did-document.js +380 -0
- package/dist/esm/utils/did-document.js.map +1 -0
- package/dist/esm/utils/general.js +195 -0
- package/dist/esm/utils/general.js.map +1 -0
- package/dist/esm/utils/identifier.js +238 -0
- package/dist/esm/utils/identifier.js.map +1 -0
- package/dist/types/bitcoin/constants.d.ts +19 -0
- package/dist/types/bitcoin/constants.d.ts.map +1 -0
- package/dist/types/bitcoin/errors.d.ts +5 -0
- package/dist/types/bitcoin/errors.d.ts.map +1 -0
- package/dist/types/bitcoin/index.d.ts +75 -0
- package/dist/types/bitcoin/index.d.ts.map +1 -0
- package/dist/types/bitcoin/interface.d.ts +86 -0
- package/dist/types/bitcoin/interface.d.ts.map +1 -0
- package/dist/types/bitcoin/network.d.ts +2 -0
- package/dist/types/bitcoin/network.d.ts.map +1 -0
- package/dist/types/bitcoin/rest-client.d.ts +268 -0
- package/dist/types/bitcoin/rest-client.d.ts.map +1 -0
- package/dist/types/bitcoin/rpc-client.d.ts +506 -0
- package/dist/types/bitcoin/rpc-client.d.ts.map +1 -0
- package/dist/types/bitcoin/taproot.d.ts +34 -0
- package/dist/types/bitcoin/taproot.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/coordinator.d.ts +74 -0
- package/dist/types/btcr2/beacon/aggregation/coordinator.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/advert.d.ts +22 -0
- package/dist/types/btcr2/beacon/aggregation/messages/advert.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/base.d.ts +36 -0
- package/dist/types/btcr2/beacon/aggregation/messages/base.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/cohort-set.d.ts +23 -0
- package/dist/types/btcr2/beacon/aggregation/messages/cohort-set.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/keygen.d.ts +6 -0
- package/dist/types/btcr2/beacon/aggregation/messages/keygen.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/opt-in.d.ts +22 -0
- package/dist/types/btcr2/beacon/aggregation/messages/opt-in.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/messages/sign.d.ts +5 -0
- package/dist/types/btcr2/beacon/aggregation/messages/sign.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/models/cohort/index.d.ts +77 -0
- package/dist/types/btcr2/beacon/aggregation/models/cohort/index.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/models/cohort/status.d.ts +7 -0
- package/dist/types/btcr2/beacon/aggregation/models/cohort/status.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/participant.d.ts +1 -0
- package/dist/types/btcr2/beacon/aggregation/participant.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/protocol/nostr.d.ts +36 -0
- package/dist/types/btcr2/beacon/aggregation/protocol/nostr.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/aggregation/protocol/service.d.ts +6 -0
- package/dist/types/btcr2/beacon/aggregation/protocol/service.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/cid-aggregate.d.ts +103 -0
- package/dist/types/btcr2/beacon/cid-aggregate.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/factory.d.ts +17 -0
- package/dist/types/btcr2/beacon/factory.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/singleton.d.ts +93 -0
- package/dist/types/btcr2/beacon/singleton.d.ts.map +1 -0
- package/dist/types/btcr2/beacon/smt-aggregate.d.ts +112 -0
- package/dist/types/btcr2/beacon/smt-aggregate.d.ts.map +1 -0
- package/dist/types/btcr2/crud/create.d.ts +92 -0
- package/dist/types/btcr2/crud/create.d.ts.map +1 -0
- package/dist/types/btcr2/crud/deactivate.d.ts +13 -0
- package/dist/types/btcr2/crud/deactivate.d.ts.map +1 -0
- package/dist/types/btcr2/crud/read.d.ts +341 -0
- package/dist/types/btcr2/crud/read.d.ts.map +1 -0
- package/dist/types/btcr2/crud/update.d.ts +83 -0
- package/dist/types/btcr2/crud/update.d.ts.map +1 -0
- package/dist/types/btcr2/key-manager/index.d.ts +145 -0
- package/dist/types/btcr2/key-manager/index.d.ts.map +1 -0
- package/dist/types/btcr2/key-manager/interface.d.ts +113 -0
- package/dist/types/btcr2/key-manager/interface.d.ts.map +1 -0
- package/dist/types/did-btcr2.d.ts +117 -0
- package/dist/types/did-btcr2.d.ts.map +1 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/interfaces/beacon.d.ts +57 -0
- package/dist/types/interfaces/beacon.d.ts.map +1 -0
- package/dist/types/interfaces/crud.d.ts +35 -0
- package/dist/types/interfaces/crud.d.ts.map +1 -0
- package/dist/types/interfaces/ibeacon.d.ts +66 -0
- package/dist/types/interfaces/ibeacon.d.ts.map +1 -0
- package/dist/types/types/bitcoin.d.ts +827 -0
- package/dist/types/types/bitcoin.d.ts.map +1 -0
- package/dist/types/types/crud.d.ts +38 -0
- package/dist/types/types/crud.d.ts.map +1 -0
- package/dist/types/utils/appendix.d.ts +118 -0
- package/dist/types/utils/appendix.d.ts.map +1 -0
- package/dist/types/utils/beacons.d.ts +156 -0
- package/dist/types/utils/beacons.d.ts.map +1 -0
- package/dist/types/utils/did-document-builder.d.ts +13 -0
- package/dist/types/utils/did-document-builder.d.ts.map +1 -0
- package/dist/types/utils/did-document.d.ts +211 -0
- package/dist/types/utils/did-document.d.ts.map +1 -0
- package/dist/types/utils/general.d.ts +85 -0
- package/dist/types/utils/general.d.ts.map +1 -0
- package/dist/types/utils/identifier.d.ts +59 -0
- package/dist/types/utils/identifier.d.ts.map +1 -0
- package/package.json +137 -0
- package/src/bitcoin/constants.ts +19 -0
- package/src/bitcoin/errors.ts +10 -0
- package/src/bitcoin/index.ts +154 -0
- package/src/bitcoin/interface.ts +160 -0
- package/src/bitcoin/network.ts +17 -0
- package/src/bitcoin/rest-client.ts +415 -0
- package/src/bitcoin/rpc-client.ts +888 -0
- package/src/bitcoin/taproot.ts +237 -0
- package/src/btcr2/beacon/aggregation/coordinator.ts +135 -0
- package/src/btcr2/beacon/aggregation/messages/advert.ts +36 -0
- package/src/btcr2/beacon/aggregation/messages/base.ts +59 -0
- package/src/btcr2/beacon/aggregation/messages/cohort-set.ts +37 -0
- package/src/btcr2/beacon/aggregation/messages/keygen.ts +8 -0
- package/src/btcr2/beacon/aggregation/messages/opt-in.ts +35 -0
- package/src/btcr2/beacon/aggregation/messages/sign.ts +7 -0
- package/src/btcr2/beacon/aggregation/models/cohort/index.ts +112 -0
- package/src/btcr2/beacon/aggregation/models/cohort/status.ts +7 -0
- package/src/btcr2/beacon/aggregation/participant.ts +0 -0
- package/src/btcr2/beacon/aggregation/protocol/nostr.ts +81 -0
- package/src/btcr2/beacon/aggregation/protocol/service.ts +6 -0
- package/src/btcr2/beacon/cid-aggregate.ts +154 -0
- package/src/btcr2/beacon/factory.ts +36 -0
- package/src/btcr2/beacon/singleton.ts +257 -0
- package/src/btcr2/beacon/smt-aggregate.ts +136 -0
- package/src/btcr2/crud/create.ts +160 -0
- package/src/btcr2/crud/deactivate.ts +13 -0
- package/src/btcr2/crud/read.ts +946 -0
- package/src/btcr2/crud/update.ts +277 -0
- package/src/btcr2/key-manager/index.ts +364 -0
- package/src/btcr2/key-manager/interface.ts +129 -0
- package/src/canonicalize.d.ts +6 -0
- package/src/did-btcr2.ts +288 -0
- package/src/index.ts +34 -0
- package/src/interfaces/beacon.ts +68 -0
- package/src/interfaces/crud.ts +36 -0
- package/src/interfaces/ibeacon.ts +76 -0
- package/src/types/bitcoin.ts +1028 -0
- package/src/types/crud.ts +41 -0
- package/src/utils/appendix.ts +257 -0
- package/src/utils/beacons.ts +276 -0
- package/src/utils/did-document-builder.ts +73 -0
- package/src/utils/did-document.ts +474 -0
- package/src/utils/general.ts +204 -0
- package/src/utils/identifier.ts +276 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import * as tinysecp from 'tiny-secp256k1';
|
|
2
|
+
import { payments, script, opcodes } from 'bitcoinjs-lib';
|
|
3
|
+
import { PublicKey } from '@did-btcr2/keypair';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Aggregate an array of public keys by point addition
|
|
7
|
+
*/
|
|
8
|
+
function aggregatePubkeys(pubkeys: Uint8Array[]): Uint8Array {
|
|
9
|
+
if (pubkeys.length === 1) return pubkeys[0];
|
|
10
|
+
return pubkeys.reduce((sum: Uint8Array, pk: Uint8Array) => {
|
|
11
|
+
const added = tinysecp.pointAdd(sum, pk);
|
|
12
|
+
if (!added) throw new Error('Point addition failed');
|
|
13
|
+
return added;
|
|
14
|
+
}, pubkeys[0]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Build a P2TR script leaf for a k-of-n multisig with optional locktime/sequence
|
|
19
|
+
*/
|
|
20
|
+
function buildTapLeafScript(
|
|
21
|
+
pubkeys: Uint8Array[],
|
|
22
|
+
k: number,
|
|
23
|
+
locktime?: number,
|
|
24
|
+
sequence?: number
|
|
25
|
+
): Uint8Array {
|
|
26
|
+
const ops: (Uint8Array | number)[] = [];
|
|
27
|
+
|
|
28
|
+
// absolute timelock
|
|
29
|
+
if (locktime !== undefined) {
|
|
30
|
+
ops.push(script.number.encode(locktime));
|
|
31
|
+
ops.push(opcodes.OP_CHECKLOCKTIMEVERIFY);
|
|
32
|
+
ops.push(opcodes.OP_DROP);
|
|
33
|
+
}
|
|
34
|
+
// relative timelock
|
|
35
|
+
if (sequence !== undefined) {
|
|
36
|
+
ops.push(script.number.encode(sequence));
|
|
37
|
+
ops.push(opcodes.OP_CHECKSEQUENCEVERIFY);
|
|
38
|
+
ops.push(opcodes.OP_DROP);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// push each key as x-only pubkey
|
|
42
|
+
for (const pk of pubkeys) {
|
|
43
|
+
const [xOnly] = PublicKey.xOnly(pk);
|
|
44
|
+
ops.push(xOnly);
|
|
45
|
+
}
|
|
46
|
+
// push threshold k and total keys n
|
|
47
|
+
ops.push(script.number.encode(k));
|
|
48
|
+
ops.push(script.number.encode(pubkeys.length));
|
|
49
|
+
ops.push(opcodes.OP_CHECKMULTISIG);
|
|
50
|
+
|
|
51
|
+
return script.compile(ops);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build a P2TR script leaf for a aggregated MuSig key (key-path only)
|
|
56
|
+
*/
|
|
57
|
+
function buildMusigLeafScript(pubkeys: Uint8Array[]): Uint8Array {
|
|
58
|
+
const agg = aggregatePubkeys(pubkeys);
|
|
59
|
+
const [xOnly] = PublicKey.xOnly(agg);
|
|
60
|
+
// In a taproot script path, OP_CHECKSIG runs schnorr
|
|
61
|
+
return script.compile([xOnly, opcodes.OP_CHECKSIG]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Recursively combine an array of leaves into a balanced Merkle tree structure
|
|
66
|
+
*/
|
|
67
|
+
function buildMerkleTree(nodes: Uint8Array[]): any {
|
|
68
|
+
if (nodes.length === 1) return { output: nodes[0] };
|
|
69
|
+
const next: any[] = [];
|
|
70
|
+
for (let i = 0; i < nodes.length; i += 2) {
|
|
71
|
+
if (i + 1 === nodes.length) {
|
|
72
|
+
next.push({ output: nodes[i] });
|
|
73
|
+
} else {
|
|
74
|
+
next.push([
|
|
75
|
+
{ output: nodes[i] },
|
|
76
|
+
{ output: nodes[i + 1] },
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return buildMerkleTree(next);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate combinations of length k from an array
|
|
85
|
+
*/
|
|
86
|
+
function* combinations<T>(array: T[], k: number): Generator<T[]> {
|
|
87
|
+
const n = array.length;
|
|
88
|
+
if (k > n || k < 0) return;
|
|
89
|
+
const indices = Array.from({ length: k }, (_, i) => i);
|
|
90
|
+
while (true) {
|
|
91
|
+
yield indices.map(i => array[i]!);
|
|
92
|
+
let i = k - 1;
|
|
93
|
+
while (i >= 0 && indices[i] === i + n - k) {
|
|
94
|
+
i--;
|
|
95
|
+
}
|
|
96
|
+
if (i < 0) break;
|
|
97
|
+
indices[i]++;
|
|
98
|
+
for (let j = i + 1; j < k; j++) {
|
|
99
|
+
indices[j] = indices[j - 1] + 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* TapRootMultiSig: builds Taproot outputs and trees for multisig and MuSig branches
|
|
106
|
+
*/
|
|
107
|
+
export class TapRootMultiSig {
|
|
108
|
+
public readonly points: Uint8Array[];
|
|
109
|
+
public readonly k: number;
|
|
110
|
+
public readonly defaultInternalPubkey: Uint8Array;
|
|
111
|
+
|
|
112
|
+
constructor(points: Uint8Array[], k: number) {
|
|
113
|
+
if (points.length < k || k < 1) {
|
|
114
|
+
throw new Error(`${k} is invalid for ${points.length} keys`);
|
|
115
|
+
}
|
|
116
|
+
this.points = points;
|
|
117
|
+
this.k = k;
|
|
118
|
+
// MuSig aggregation for default internal key
|
|
119
|
+
this.defaultInternalPubkey = aggregatePubkeys(points);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Single multisig leaf as the only script path
|
|
124
|
+
*/
|
|
125
|
+
singleLeaf(locktime?: number, sequence?: number) {
|
|
126
|
+
const leaf = buildTapLeafScript(this.points, this.k, locktime, sequence);
|
|
127
|
+
return payments.p2tr({
|
|
128
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
129
|
+
scriptTree : { output: leaf },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* All k-of-n multisig combinations as separate leaf scripts, combined into one tree
|
|
135
|
+
*/
|
|
136
|
+
multiLeafTree(locktime?: number, sequence?: number) {
|
|
137
|
+
const leaves: Uint8Array[] = [];
|
|
138
|
+
for (const combo of combinations(this.points, this.k)) {
|
|
139
|
+
leaves.push(buildTapLeafScript(combo, this.k, locktime, sequence));
|
|
140
|
+
}
|
|
141
|
+
const tree = buildMerkleTree(leaves);
|
|
142
|
+
return payments.p2tr({
|
|
143
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
144
|
+
scriptTree : tree,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* MuSig key-path scripts for each k-of-n combination in the script tree
|
|
150
|
+
*/
|
|
151
|
+
musigTree() {
|
|
152
|
+
const leaves: Uint8Array[] = [];
|
|
153
|
+
for (const combo of combinations(this.points, this.k)) {
|
|
154
|
+
leaves.push(buildMusigLeafScript(combo));
|
|
155
|
+
}
|
|
156
|
+
const tree = buildMerkleTree(leaves);
|
|
157
|
+
return payments.p2tr({
|
|
158
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
159
|
+
scriptTree : tree,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* A two-branch tree: one branch is the singleLeaf script, the other is the muSig tree
|
|
165
|
+
*/
|
|
166
|
+
musigAndSingleLeafTree(locktime?: number, sequence?: number) {
|
|
167
|
+
const single = buildTapLeafScript(this.points, this.k, locktime, sequence);
|
|
168
|
+
const musigLeaves: Uint8Array[] = [];
|
|
169
|
+
for (const combo of combinations(this.points, this.k)) {
|
|
170
|
+
musigLeaves.push(buildMusigLeafScript(combo));
|
|
171
|
+
}
|
|
172
|
+
const tree = {
|
|
173
|
+
output : single,
|
|
174
|
+
scriptTree : buildMerkleTree(musigLeaves),
|
|
175
|
+
};
|
|
176
|
+
return payments.p2tr({
|
|
177
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
178
|
+
scriptTree : tree,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Nested tree of singleLeaf, multiLeafTree, and musigTree
|
|
184
|
+
*/
|
|
185
|
+
everythingTree(locktime?: number, sequence?: number) {
|
|
186
|
+
const single = buildTapLeafScript(this.points, this.k, locktime, sequence);
|
|
187
|
+
|
|
188
|
+
const multiLeaves: Uint8Array[] = [];
|
|
189
|
+
for (const combo of combinations(this.points, this.k)) {
|
|
190
|
+
multiLeaves.push(buildTapLeafScript(combo, this.k, locktime, sequence));
|
|
191
|
+
}
|
|
192
|
+
const multiTree = buildMerkleTree(multiLeaves);
|
|
193
|
+
|
|
194
|
+
const musigLeaves: Uint8Array[] = [];
|
|
195
|
+
for (const combo of combinations(this.points, this.k)) {
|
|
196
|
+
musigLeaves.push(buildMusigLeafScript(combo));
|
|
197
|
+
}
|
|
198
|
+
const musigTree = buildMerkleTree(musigLeaves);
|
|
199
|
+
|
|
200
|
+
const tree = {
|
|
201
|
+
output : single,
|
|
202
|
+
scriptTree : [multiTree, musigTree],
|
|
203
|
+
};
|
|
204
|
+
return payments.p2tr({
|
|
205
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
206
|
+
scriptTree : tree,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Degrading multisig: k-of-n initially, then (k-1)-of-n after delay, ... until 1-of-n
|
|
212
|
+
*/
|
|
213
|
+
degradingMultisigTree(
|
|
214
|
+
sequenceBlockInterval?: number,
|
|
215
|
+
sequenceTimeInterval?: number
|
|
216
|
+
) {
|
|
217
|
+
const leaves: Uint8Array[] = [];
|
|
218
|
+
for (let num = this.k; num >= 1; num--) {
|
|
219
|
+
let seq: number | undefined;
|
|
220
|
+
if (num === this.k) {
|
|
221
|
+
seq = undefined;
|
|
222
|
+
} else if (sequenceBlockInterval != null) {
|
|
223
|
+
seq = sequenceBlockInterval * (this.k - num);
|
|
224
|
+
} else if (sequenceTimeInterval != null) {
|
|
225
|
+
seq = sequenceTimeInterval * (this.k - num);
|
|
226
|
+
}
|
|
227
|
+
for (const combo of combinations(this.points, num)) {
|
|
228
|
+
leaves.push(buildTapLeafScript(combo, num, undefined, seq));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const tree = buildMerkleTree(leaves);
|
|
232
|
+
return payments.p2tr({
|
|
233
|
+
internalPubkey : this.defaultInternalPubkey,
|
|
234
|
+
scriptTree : tree,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Base } from './messages/base.js';
|
|
2
|
+
import { OptInMessage } from './messages/opt-in.js';
|
|
3
|
+
import { OPT_IN, SUBSCRIBE, SUBSCRIBE_ACCEPT } from './messages/keygen.js';
|
|
4
|
+
import { Musig2Cohort } from './models/cohort/index.js';
|
|
5
|
+
import { NostrAdapter } from './protocol/nostr.js';
|
|
6
|
+
import { ProtocolService } from './protocol/service.js';
|
|
7
|
+
import { NONCE_CONTRIBUTION, REQUEST_SIGNATURE, SIGNATURE_AUTHORIZATION } from './messages/sign.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The BeaconCoordinator class is responsible for managing the coordination of beacon aggregation.
|
|
11
|
+
* @class BeaconCoordinator
|
|
12
|
+
* @type {BeaconCoordinator}
|
|
13
|
+
*/
|
|
14
|
+
export class BeaconCoordinator {
|
|
15
|
+
/**
|
|
16
|
+
* The name of the BeaconCoordinator service.
|
|
17
|
+
* @type {string}
|
|
18
|
+
*/
|
|
19
|
+
public name: string = 'BeaconCoordinator';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The DID of the BeaconCoordinator.
|
|
23
|
+
* @type {Array<string>}
|
|
24
|
+
*/
|
|
25
|
+
public did: string = '';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The protocol service used for communication.
|
|
29
|
+
* @type {ProtocolService}
|
|
30
|
+
*/
|
|
31
|
+
public protocol: ProtocolService;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* List of subscribers to the BeaconCoordinator service.
|
|
35
|
+
* @type {Array<string>}
|
|
36
|
+
*/
|
|
37
|
+
public cohorts: Array<Musig2Cohort> = [];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* List of subscribers to the BeaconCoordinator service.
|
|
41
|
+
* @type {Array<string>}
|
|
42
|
+
*/
|
|
43
|
+
private subscribers: string[] = [];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Constructs a new BeaconCoordinator instance.
|
|
47
|
+
* @param {ProtocolService} protocol The protocol service used for communication.
|
|
48
|
+
* @param {string} [did] Optional DID to use for the coordinator. If not provided, a new DID will be generated.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
constructor(protocol: ProtocolService, did?: string) {
|
|
52
|
+
this.protocol = protocol ?? new NostrAdapter();
|
|
53
|
+
this.setup(did);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Sets up the BeaconCoordinator by registering message handlers and optionally generating a DID.
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
public setup(did?: string): void {
|
|
61
|
+
this.did = did || this.protocol.generateIdentity();
|
|
62
|
+
this.protocol.registerMessageHandler(SUBSCRIBE, this._handleSubscribe.bind(this));
|
|
63
|
+
this.protocol.registerMessageHandler(OPT_IN, this._handleOptIn.bind(this));
|
|
64
|
+
this.protocol.registerMessageHandler(REQUEST_SIGNATURE, this._handleSubscribe.bind(this));
|
|
65
|
+
this.protocol.registerMessageHandler(NONCE_CONTRIBUTION, this._handleSubscribe.bind(this));
|
|
66
|
+
this.protocol.registerMessageHandler(SIGNATURE_AUTHORIZATION, this._handleSubscribe.bind(this));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Initializes the BeaconCoordinator by setting up the protocol and starting it.
|
|
71
|
+
* @param {string} [did] Optional DID to use for the coordinator. If not provided, the existing DID will be used.
|
|
72
|
+
*/
|
|
73
|
+
async initialize(did?: string): Promise<void> {
|
|
74
|
+
this.setup(did);
|
|
75
|
+
await this.protocol.start();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handles subscription requests from other participants.
|
|
80
|
+
* @param {Base} message The message containing the subscription request.
|
|
81
|
+
* @returns {Promise<void>}
|
|
82
|
+
*/
|
|
83
|
+
private async _handleSubscribe(message: Base): Promise<void> {
|
|
84
|
+
const sender = message.from;
|
|
85
|
+
if (!this.subscribers.includes(sender)) {
|
|
86
|
+
this.subscribers.push(sender);
|
|
87
|
+
await this.acceptSubscription(sender);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handles opt-in requests from participants to join a cohort.
|
|
93
|
+
* @param {any} message The message containing the opt-in request.
|
|
94
|
+
* @returns {Promise<void>}
|
|
95
|
+
*/
|
|
96
|
+
private async _handleOptIn(message: any): Promise<void> {
|
|
97
|
+
const optIn = OptInMessage.fromJSON(message);
|
|
98
|
+
const cohortId = optIn.cohortId;
|
|
99
|
+
const participant = optIn.from;
|
|
100
|
+
const participantPk = optIn.participantPk;
|
|
101
|
+
const cohort = this.cohorts.find(c => c.id === cohortId);
|
|
102
|
+
if (cohort && !cohort.participants.includes(participant)) {
|
|
103
|
+
cohort.participants.push(participant);
|
|
104
|
+
cohort.cohortKeys.push(participantPk);
|
|
105
|
+
await this.acceptSubscription(participant);
|
|
106
|
+
if (cohort.participants.length >= cohort.minParticipants) {
|
|
107
|
+
await this._startKeyGeneration(cohort);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Starts the key generation process for a cohort once it has enough participants.
|
|
114
|
+
* @param {Musig2Cohort} cohort The cohort for which to start key generation.
|
|
115
|
+
* @returns {Promise<void>}
|
|
116
|
+
*/
|
|
117
|
+
private async _startKeyGeneration(cohort: Musig2Cohort): Promise<void> {
|
|
118
|
+
cohort.finalize();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Accepts a subscription request from a participant.
|
|
123
|
+
* @param {string} sender The DID of the participant requesting the subscription.
|
|
124
|
+
* @returns {Promise<void>}
|
|
125
|
+
*/
|
|
126
|
+
public async acceptSubscription(sender: string): Promise<void> {
|
|
127
|
+
console.log(`Accepting subscription from ${sender}`);
|
|
128
|
+
const response = {
|
|
129
|
+
type : SUBSCRIBE_ACCEPT,
|
|
130
|
+
to : sender,
|
|
131
|
+
from : this.did
|
|
132
|
+
};
|
|
133
|
+
await this.protocol.sendMessage(response, sender, this.did);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseMessage } from './base.js';
|
|
2
|
+
|
|
3
|
+
export type Advert = {
|
|
4
|
+
type?: 'BEACON_ADVERT';
|
|
5
|
+
to: string;
|
|
6
|
+
from: string;
|
|
7
|
+
cohortId: string;
|
|
8
|
+
cohortSize: number;
|
|
9
|
+
network: string;
|
|
10
|
+
threadId?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class AdvertMessage extends BaseMessage {
|
|
14
|
+
public cohortId: string;
|
|
15
|
+
public cohortSize: number;
|
|
16
|
+
public network: string = 'signet';
|
|
17
|
+
|
|
18
|
+
constructor({ type = 'BEACON_ADVERT', to, from, threadId, cohortId, cohortSize, network }: Advert) {
|
|
19
|
+
super({ type, to, from, threadId, body: { cohortId, cohortSize, network }});
|
|
20
|
+
this.cohortId = cohortId;
|
|
21
|
+
this.cohortSize = cohortSize;
|
|
22
|
+
this.network = network;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initializes an AdvertMessage from a given Advert object.
|
|
27
|
+
* @param {Advert} data - The Advert object to initialize the AdvertMessage.
|
|
28
|
+
* @returns {object} The serialized AdvertMessage.
|
|
29
|
+
*/
|
|
30
|
+
public static initialize(data: Advert): AdvertMessage {
|
|
31
|
+
if (data.type != 'BEACON_ADVERT'){
|
|
32
|
+
throw new Error(`Invalid type: ${data.type}`);
|
|
33
|
+
}
|
|
34
|
+
return new AdvertMessage(data);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Maybe } from '@did-btcr2/common';
|
|
2
|
+
|
|
3
|
+
export const MESSAGE_PREFIX = 'https://btcr2.tools/';
|
|
4
|
+
|
|
5
|
+
export type BaseBody = {
|
|
6
|
+
cohortId: string;
|
|
7
|
+
cohortSize?: number;
|
|
8
|
+
network?: string;
|
|
9
|
+
participantPk?: Uint8Array;
|
|
10
|
+
beaconAddress?: string;
|
|
11
|
+
cohortKeys?: Array<Uint8Array>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type Base = {
|
|
15
|
+
type: string;
|
|
16
|
+
to: string;
|
|
17
|
+
from: string;
|
|
18
|
+
threadId?: string;
|
|
19
|
+
body: BaseBody;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export class BaseMessage {
|
|
23
|
+
public type: string;
|
|
24
|
+
public to: string;
|
|
25
|
+
public from: string;
|
|
26
|
+
public threadId?: string;
|
|
27
|
+
public body: BaseBody;
|
|
28
|
+
|
|
29
|
+
constructor({ type, to, from, threadId, body }: Base) {
|
|
30
|
+
this.type = type;
|
|
31
|
+
this.to = to;
|
|
32
|
+
this.from = from;
|
|
33
|
+
this.threadId = threadId;
|
|
34
|
+
this.body = body;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a BaseMessage from a JSON object.
|
|
39
|
+
* @param {Maybe<Base>} data - The JSON object to initialize the BaseMessage.
|
|
40
|
+
* @returns {BaseMessage} The initialized BaseMessage.
|
|
41
|
+
*/
|
|
42
|
+
public static fromJSON(data: Maybe<Base>): BaseMessage {
|
|
43
|
+
return new BaseMessage(data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Converts a BaseMessage to a JSON object.
|
|
48
|
+
* @returns {Base} The JSON representation of the BaseMessage.
|
|
49
|
+
*/
|
|
50
|
+
public json(): Base {
|
|
51
|
+
return {
|
|
52
|
+
type : this.type,
|
|
53
|
+
to : this.to,
|
|
54
|
+
from : this.from,
|
|
55
|
+
threadId : this.threadId,
|
|
56
|
+
body : this.body ?? {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseMessage } from './base.js';
|
|
2
|
+
import { COHORT_SET } from './keygen.js';
|
|
3
|
+
|
|
4
|
+
export type CohortSet = {
|
|
5
|
+
type?: typeof COHORT_SET;
|
|
6
|
+
to: string;
|
|
7
|
+
from: string;
|
|
8
|
+
cohortId: string;
|
|
9
|
+
beaconAddress: string;
|
|
10
|
+
cohortKeys: Array<Uint8Array>;
|
|
11
|
+
threadId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class CohortSetMessage extends BaseMessage {
|
|
15
|
+
public cohortId: string;
|
|
16
|
+
public beaconAddress: string;
|
|
17
|
+
public cohortKeys: Array<Uint8Array>;
|
|
18
|
+
|
|
19
|
+
constructor({ type = COHORT_SET, to, from, threadId, cohortId, beaconAddress, cohortKeys }: CohortSet) {
|
|
20
|
+
super({ type, to, from, threadId, body: { cohortId, beaconAddress, cohortKeys }});
|
|
21
|
+
this.cohortId = cohortId;
|
|
22
|
+
this.beaconAddress = beaconAddress;
|
|
23
|
+
this.cohortKeys = cohortKeys;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initializes an CohortSetMessage from a given OptIn object.
|
|
28
|
+
* @param {OptIn} data - The OptIn object to initialize the CohortSetMessage.
|
|
29
|
+
* @returns {object} The serialized CohortSetMessage.
|
|
30
|
+
*/
|
|
31
|
+
public static fromJSON(data: CohortSet): CohortSetMessage {
|
|
32
|
+
if (data.type !== COHORT_SET) {
|
|
33
|
+
throw new Error(`Invalid type: ${data.type}`);
|
|
34
|
+
}
|
|
35
|
+
return new CohortSetMessage(data);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MESSAGE_PREFIX } from './base.js';
|
|
2
|
+
|
|
3
|
+
export const COHORT_ADVERT = `${MESSAGE_PREFIX}musig2/keygen/cohort_advert`;
|
|
4
|
+
export const COHORT_INVITE = `${MESSAGE_PREFIX}musig2/keygen/cohort_invite`;
|
|
5
|
+
export const OPT_IN = `${MESSAGE_PREFIX}musig2/keygen/opt_in`;
|
|
6
|
+
export const COHORT_SET = `${MESSAGE_PREFIX}musig2/keygen/cohort_set`;
|
|
7
|
+
export const SUBSCRIBE = `${MESSAGE_PREFIX}musig2/keygen/subscribe`;
|
|
8
|
+
export const SUBSCRIBE_ACCEPT = `${MESSAGE_PREFIX}musig2/keygen/subscribe_accept`;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Maybe } from '@did-btcr2/common';
|
|
2
|
+
import { BaseMessage } from './base.js';
|
|
3
|
+
import { OPT_IN } from './keygen.js';
|
|
4
|
+
|
|
5
|
+
export type OptIn = {
|
|
6
|
+
type: typeof OPT_IN;
|
|
7
|
+
to: string;
|
|
8
|
+
from: string;
|
|
9
|
+
cohortId: string;
|
|
10
|
+
participantPk: Uint8Array;
|
|
11
|
+
threadId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class OptInMessage extends BaseMessage {
|
|
15
|
+
public cohortId: string;
|
|
16
|
+
public participantPk: Uint8Array;
|
|
17
|
+
|
|
18
|
+
constructor({ type = OPT_IN, to, from, threadId, cohortId, participantPk }: OptIn) {
|
|
19
|
+
super({ type, to, from, threadId, body: { cohortId, participantPk }});
|
|
20
|
+
this.cohortId = cohortId;
|
|
21
|
+
this.participantPk = participantPk;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initializes an OptInMessage from a given OptIn object.
|
|
26
|
+
* @param {OptIn} data - The OptIn object to initialize the OptInMessage.
|
|
27
|
+
* @returns {object} The serialized OptInMessage.
|
|
28
|
+
*/
|
|
29
|
+
public static fromJSON(data: Maybe<OptIn>): OptInMessage {
|
|
30
|
+
if (data.type != 'OPT_IN') {
|
|
31
|
+
throw new Error(`Invalid type: ${data.type}`);
|
|
32
|
+
}
|
|
33
|
+
return new OptInMessage(data);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { MESSAGE_PREFIX } from './base.js';
|
|
2
|
+
|
|
3
|
+
export const REQUEST_SIGNATURE = `${MESSAGE_PREFIX}musig2/sign/request_signature`;
|
|
4
|
+
export const AUTHORIZATION_REQUEST = `${MESSAGE_PREFIX}musig2/sign/authorization_request`;
|
|
5
|
+
export const NONCE_CONTRIBUTION = `${MESSAGE_PREFIX}musig2/sign/nonce_contribution`;
|
|
6
|
+
export const AGGREGATED_NONCE = `${MESSAGE_PREFIX}musig2/sign/aggregated_nonce`;
|
|
7
|
+
export const SIGNATURE_AUTHORIZATION = `${MESSAGE_PREFIX}musig2/sign/signature_authorization`;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { TapRootMultiSig } from '../../../../../bitcoin/taproot.js';
|
|
2
|
+
import { COHORT_STATUS, COHORT_STATUS_TYPE } from './status.js';
|
|
3
|
+
|
|
4
|
+
export type Musig2CohortParams = {
|
|
5
|
+
id?: string;
|
|
6
|
+
minParticipants: number;
|
|
7
|
+
status: COHORT_STATUS_TYPE;
|
|
8
|
+
network: string;
|
|
9
|
+
coordinatorDid: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Musig2Cohort {
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for the cohort.
|
|
15
|
+
* @type {string}
|
|
16
|
+
*/
|
|
17
|
+
public id: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* DID of the coordinator.
|
|
21
|
+
* @type {string}
|
|
22
|
+
*/
|
|
23
|
+
public coordinatorDid: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Minimum number of participants required to finalize the cohort.
|
|
27
|
+
* @type {number}
|
|
28
|
+
*/
|
|
29
|
+
public minParticipants: number;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Status of the cohort.
|
|
33
|
+
* @type {string}
|
|
34
|
+
*/
|
|
35
|
+
public status: COHORT_STATUS_TYPE;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Network on which the cohort operates (e.g., 'mainnet', 'testnet').
|
|
39
|
+
* @type {string}
|
|
40
|
+
*/
|
|
41
|
+
public network: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Pending signature requests, mapping participant DIDs to their pending signatures.
|
|
45
|
+
* @type {Record<string, string>}
|
|
46
|
+
*/
|
|
47
|
+
public pendingSignatureRequests: Record<string, string> = {};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* List of participant DIDs.
|
|
51
|
+
* @type {Array<string>}
|
|
52
|
+
*/
|
|
53
|
+
public participants: Array<string> = new Array<string>();
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* List of cohort keys (public keys).
|
|
57
|
+
* @type {Array<Uint8Array>}
|
|
58
|
+
*/
|
|
59
|
+
public cohortKeys: Array<Uint8Array> = new Array<Uint8Array>();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Taproot Merkle root for the cohort.
|
|
63
|
+
* @type {Uint8Array}
|
|
64
|
+
*/
|
|
65
|
+
public trMerkleRoot?: Uint8Array;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Beacon address for the cohort, calculated from the Taproot multisig.
|
|
69
|
+
* @type {string}
|
|
70
|
+
*/
|
|
71
|
+
public beaconAddress?: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new Musig2Cohort instance.
|
|
75
|
+
* @param {Musig2CohortParams} params Parameters for initializing the cohort.
|
|
76
|
+
* @param {string} [params.id] Optional unique identifier for the cohort. If not provided, a random UUID will be generated.
|
|
77
|
+
* @param {number} params.minParticipants Minimum number of participants required to finalize the cohort.
|
|
78
|
+
* @param {string} params.coordinatorDid DID of the coordinator managing the cohort.
|
|
79
|
+
* @param {string} params.status Initial status of the cohort (e.g., 'PENDING', 'COHORT_SET').
|
|
80
|
+
* @param {string} params.network Network on which the cohort operates (e.g., 'mainnet', 'testnet').
|
|
81
|
+
*/
|
|
82
|
+
constructor(params: Musig2CohortParams) {
|
|
83
|
+
this.id = params.id || crypto.randomUUID();
|
|
84
|
+
this.minParticipants = params.minParticipants;
|
|
85
|
+
this.coordinatorDid = params.coordinatorDid;
|
|
86
|
+
this.status = params.status as COHORT_STATUS_TYPE || COHORT_STATUS.COHORT_ADVERTISED;
|
|
87
|
+
this.network = params.network;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public finalize(): void {
|
|
91
|
+
if(this.participants.length < this.minParticipants) {
|
|
92
|
+
throw new Error('Not enough participants to finalize the cohort');
|
|
93
|
+
}
|
|
94
|
+
this.status = COHORT_STATUS.COHORT_SET_STATUS;
|
|
95
|
+
this.beaconAddress = this.calulateBeaconAddress();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Calculates the beacon Taproot multisig address for the cohort using participant keys.
|
|
100
|
+
* @returns {string} The Taproot address for the cohort.
|
|
101
|
+
* @throws {Error} If the Taproot address cannot be calculated.
|
|
102
|
+
*/
|
|
103
|
+
public calulateBeaconAddress(): string {
|
|
104
|
+
const trMultisig = new TapRootMultiSig(this.cohortKeys, this.cohortKeys.length);
|
|
105
|
+
const branch = trMultisig.musigTree();
|
|
106
|
+
this.trMerkleRoot = branch.hash;
|
|
107
|
+
if(!branch.address) {
|
|
108
|
+
throw new Error('Failed to calculate Taproot address');
|
|
109
|
+
}
|
|
110
|
+
return branch.address;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
File without changes
|