@did-btcr2/method 0.33.0 → 0.35.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 +371 -119
- package/dist/browser.mjs +371 -119
- package/dist/cjs/index.js +326 -81
- package/dist/esm/core/aggregation/cohort.js +5 -1
- package/dist/esm/core/aggregation/cohort.js.map +1 -1
- package/dist/esm/core/aggregation/participant.js +25 -8
- package/dist/esm/core/aggregation/participant.js.map +1 -1
- package/dist/esm/core/aggregation/runner/aggregation-runner.js +66 -0
- package/dist/esm/core/aggregation/runner/aggregation-runner.js.map +1 -0
- package/dist/esm/core/aggregation/runner/index.js +1 -0
- package/dist/esm/core/aggregation/runner/index.js.map +1 -1
- package/dist/esm/core/aggregation/runner/participant-runner.js +9 -1
- package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -1
- package/dist/esm/core/aggregation/runner/service-runner.js +4 -1
- package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -1
- package/dist/esm/core/aggregation/service.js +4 -4
- package/dist/esm/core/aggregation/service.js.map +1 -1
- package/dist/esm/core/aggregation/signer.js +33 -0
- package/dist/esm/core/aggregation/signer.js.map +1 -0
- package/dist/esm/core/aggregation/signing-session.js +34 -11
- package/dist/esm/core/aggregation/signing-session.js.map +1 -1
- package/dist/esm/core/aggregation/transport/in-memory.js +149 -0
- package/dist/esm/core/aggregation/transport/in-memory.js.map +1 -0
- package/dist/esm/core/aggregation/transport/index.js +1 -0
- package/dist/esm/core/aggregation/transport/index.js.map +1 -1
- package/dist/esm/core/beacon/beacon.js +10 -8
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/cas-beacon.js +4 -4
- 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/singleton-beacon.js +4 -4
- package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
- package/dist/esm/core/beacon/smt-beacon.js +4 -4
- package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/aggregation/cohort.d.ts.map +1 -1
- package/dist/types/core/aggregation/participant.d.ts +17 -4
- package/dist/types/core/aggregation/participant.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/aggregation-runner.d.ts +56 -0
- package/dist/types/core/aggregation/runner/aggregation-runner.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/index.d.ts +1 -0
- package/dist/types/core/aggregation/runner/index.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -1
- package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -1
- package/dist/types/core/aggregation/service.d.ts +10 -4
- package/dist/types/core/aggregation/service.d.ts.map +1 -1
- package/dist/types/core/aggregation/signer.d.ts +50 -0
- package/dist/types/core/aggregation/signer.d.ts.map +1 -0
- package/dist/types/core/aggregation/signing-session.d.ts +13 -5
- package/dist/types/core/aggregation/signing-session.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/in-memory.d.ts +64 -0
- package/dist/types/core/aggregation/transport/in-memory.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/index.d.ts +1 -0
- package/dist/types/core/aggregation/transport/index.d.ts.map +1 -1
- package/dist/types/core/beacon/beacon.d.ts +12 -10
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/cas-beacon.d.ts +4 -4
- package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/factory.d.ts +3 -3
- package/dist/types/core/beacon/factory.d.ts.map +1 -1
- package/dist/types/core/beacon/singleton-beacon.d.ts +4 -4
- package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/smt-beacon.d.ts +4 -4
- package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
- package/dist/types/core/resolver.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/core/aggregation/cohort.ts +5 -1
- package/src/core/aggregation/participant.ts +38 -12
- package/src/core/aggregation/runner/aggregation-runner.ts +96 -0
- package/src/core/aggregation/runner/index.ts +1 -0
- package/src/core/aggregation/runner/participant-runner.ts +9 -1
- package/src/core/aggregation/runner/service-runner.ts +4 -1
- package/src/core/aggregation/service.ts +12 -6
- package/src/core/aggregation/signer.ts +67 -0
- package/src/core/aggregation/signing-session.ts +34 -11
- package/src/core/aggregation/transport/in-memory.ts +178 -0
- package/src/core/aggregation/transport/index.ts +1 -0
- package/src/core/beacon/beacon.ts +12 -10
- package/src/core/beacon/cas-beacon.ts +4 -4
- package/src/core/beacon/factory.ts +3 -3
- package/src/core/beacon/singleton-beacon.ts +4 -4
- package/src/core/beacon/smt-beacon.ts +4 -4
- package/src/core/resolver.ts +1 -1
- package/src/index.ts +1 -0
package/dist/cjs/index.js
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
AggregationParticipant: () => AggregationParticipant,
|
|
41
41
|
AggregationParticipantError: () => AggregationParticipantError,
|
|
42
42
|
AggregationParticipantRunner: () => AggregationParticipantRunner,
|
|
43
|
+
AggregationRunner: () => AggregationRunner,
|
|
43
44
|
AggregationService: () => AggregationService,
|
|
44
45
|
AggregationServiceError: () => AggregationServiceError,
|
|
45
46
|
AggregationServiceRunner: () => AggregationServiceRunner,
|
|
@@ -47,7 +48,6 @@ __export(index_exports, {
|
|
|
47
48
|
BECH32M_CHARS: () => BECH32M_CHARS,
|
|
48
49
|
BTCR2_DID_DOCUMENT_CONTEXT: () => BTCR2_DID_DOCUMENT_CONTEXT,
|
|
49
50
|
BaseMessage: () => BaseMessage,
|
|
50
|
-
Beacon: () => Beacon,
|
|
51
51
|
BeaconError: () => BeaconError,
|
|
52
52
|
BeaconFactory: () => BeaconFactory,
|
|
53
53
|
BeaconSignalDiscovery: () => BeaconSignalDiscovery,
|
|
@@ -82,8 +82,11 @@ __export(index_exports, {
|
|
|
82
82
|
HttpTransportError: () => HttpTransportError,
|
|
83
83
|
ID_PLACEHOLDER_VALUE: () => ID_PLACEHOLDER_VALUE,
|
|
84
84
|
Identifier: () => Identifier,
|
|
85
|
+
InMemoryBus: () => InMemoryBus,
|
|
85
86
|
InMemoryRateLimitStore: () => InMemoryRateLimitStore,
|
|
87
|
+
InMemoryTransport: () => InMemoryTransport,
|
|
86
88
|
InboxBuffer: () => InboxBuffer,
|
|
89
|
+
KeyPairAggregationSigner: () => KeyPairAggregationSigner,
|
|
87
90
|
NONCE_CONTRIBUTION: () => NONCE_CONTRIBUTION,
|
|
88
91
|
NonceCache: () => NonceCache,
|
|
89
92
|
NostrTransport: () => NostrTransport,
|
|
@@ -104,6 +107,7 @@ __export(index_exports, {
|
|
|
104
107
|
ServiceCohortPhase: () => ServiceCohortPhase,
|
|
105
108
|
SigningSessionError: () => SigningSessionError,
|
|
106
109
|
SigningSessionPhase: () => SigningSessionPhase,
|
|
110
|
+
SinglePartyBeacon: () => SinglePartyBeacon,
|
|
107
111
|
SingletonBeacon: () => SingletonBeacon,
|
|
108
112
|
SingletonBeaconError: () => SingletonBeaconError,
|
|
109
113
|
StaticFeeEstimator: () => StaticFeeEstimator,
|
|
@@ -221,6 +225,7 @@ function getBeaconStrategy(type) {
|
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
// src/core/aggregation/cohort.ts
|
|
228
|
+
var import_bitcoin = require("@did-btcr2/bitcoin");
|
|
224
229
|
var import_common3 = require("@did-btcr2/common");
|
|
225
230
|
var import_smt2 = require("@did-btcr2/smt");
|
|
226
231
|
var import_secp256k1 = require("@noble/curves/secp256k1.js");
|
|
@@ -322,7 +327,7 @@ var AggregationCohort = class {
|
|
|
322
327
|
}
|
|
323
328
|
const keyAggContext = (0, import_musig2.keyAggregate)(this.#cohortKeys);
|
|
324
329
|
const aggPubkey = (0, import_musig2.keyAggExport)(keyAggContext);
|
|
325
|
-
const payment = (0, import_btc_signer.p2tr)(aggPubkey);
|
|
330
|
+
const payment = (0, import_btc_signer.p2tr)(aggPubkey, void 0, (0, import_bitcoin.getNetwork)(this.network));
|
|
326
331
|
this.tapTweak = import_secp256k1.schnorr.utils.taggedHash("TapTweak", aggPubkey);
|
|
327
332
|
if (!payment.address) {
|
|
328
333
|
throw new AggregationCohortError(
|
|
@@ -593,6 +598,7 @@ var SigningSessionPhase = /* @__PURE__ */ ((SigningSessionPhase2) => {
|
|
|
593
598
|
})(SigningSessionPhase || {});
|
|
594
599
|
|
|
595
600
|
// src/core/aggregation/signing-session.ts
|
|
601
|
+
var import_keypair = require("@did-btcr2/keypair");
|
|
596
602
|
var import_btc_signer2 = require("@scure/btc-signer");
|
|
597
603
|
var musig2 = __toESM(require("@scure/btc-signer/musig2"), 1);
|
|
598
604
|
var BeaconSigningSession = class {
|
|
@@ -616,8 +622,14 @@ var BeaconSigningSession = class {
|
|
|
616
622
|
signature;
|
|
617
623
|
/** Current signing session phase. */
|
|
618
624
|
phase;
|
|
619
|
-
/**
|
|
620
|
-
|
|
625
|
+
/**
|
|
626
|
+
* Participant's MuSig2 secret nonce, held only on the participant side
|
|
627
|
+
* between {@link generateNonceContribution} and {@link generatePartialSignature}.
|
|
628
|
+
* Private and cleared on every terminal path (success, failure, or teardown
|
|
629
|
+
* via {@link clearSecrets}) so a spent or abandoned nonce cannot be reused or
|
|
630
|
+
* serialized.
|
|
631
|
+
*/
|
|
632
|
+
#secretNonce;
|
|
621
633
|
constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }) {
|
|
622
634
|
this.id = id || crypto.randomUUID();
|
|
623
635
|
this.cohort = cohort;
|
|
@@ -769,22 +781,24 @@ var BeaconSigningSession = class {
|
|
|
769
781
|
generateNonceContribution(participantPublicKey, participantSecretKey) {
|
|
770
782
|
const aggPublicKey = musig2.keyAggExport(musig2.keyAggregate(this.cohort.cohortKeys));
|
|
771
783
|
const nonces = musig2.nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
|
|
772
|
-
this
|
|
784
|
+
this.#secretNonce = nonces.secret;
|
|
773
785
|
return nonces.public;
|
|
774
786
|
}
|
|
775
787
|
/**
|
|
776
788
|
* Generates a partial signature using the participant's secret key + secret nonce.
|
|
777
789
|
* Requires the aggregated nonce to have been set first (via the service).
|
|
778
790
|
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
*
|
|
791
|
+
* Clears the stored secret nonce after use on every path (success or throw)
|
|
792
|
+
* via {@link clearSecrets}. JS cannot truly erase memory (GC may relocate
|
|
793
|
+
* buffers), but overwriting the bytes shortens the exposure window and
|
|
794
|
+
* prevents accidental reuse or serialization of a spent nonce - reuse of a
|
|
795
|
+
* MuSig2 nonce leaks the secret key.
|
|
782
796
|
*/
|
|
783
797
|
generatePartialSignature(participantSecretKey) {
|
|
784
798
|
if (!this.aggregatedNonce) {
|
|
785
799
|
throw new SigningSessionError("Aggregated nonce not available.", "MISSING_AGGREGATED_NONCE");
|
|
786
800
|
}
|
|
787
|
-
if (!this
|
|
801
|
+
if (!this.#secretNonce) {
|
|
788
802
|
throw new SigningSessionError("Secret nonce not available \u2014 generateNonceContribution() must be called first.", "MISSING_SECRET_NONCE");
|
|
789
803
|
}
|
|
790
804
|
const session = new musig2.Session(
|
|
@@ -794,10 +808,23 @@ var BeaconSigningSession = class {
|
|
|
794
808
|
[this.cohort.tapTweak],
|
|
795
809
|
[true]
|
|
796
810
|
);
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
811
|
+
try {
|
|
812
|
+
return session.sign(this.#secretNonce, participantSecretKey);
|
|
813
|
+
} finally {
|
|
814
|
+
this.clearSecrets();
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Zeroize any retained secret nonce. Safe to call repeatedly and on any path
|
|
819
|
+
* (completion, failure, or teardown of an abandoned session). Callers that
|
|
820
|
+
* drop a session before it reaches a partial signature should invoke this so
|
|
821
|
+
* the secret nonce does not linger on the live object.
|
|
822
|
+
*/
|
|
823
|
+
clearSecrets() {
|
|
824
|
+
if (this.#secretNonce) {
|
|
825
|
+
(0, import_keypair.wipe)(this.#secretNonce);
|
|
826
|
+
this.#secretNonce = void 0;
|
|
827
|
+
}
|
|
801
828
|
}
|
|
802
829
|
isComplete() {
|
|
803
830
|
return this.phase === "Complete" /* Complete */;
|
|
@@ -811,13 +838,13 @@ var BeaconSigningSession = class {
|
|
|
811
838
|
var DEFAULT_MAX_UPDATE_SIZE_BYTES = 256 * 1024;
|
|
812
839
|
var AggregationService = class {
|
|
813
840
|
did;
|
|
814
|
-
|
|
841
|
+
publicKey;
|
|
815
842
|
maxUpdateSizeBytes;
|
|
816
843
|
/** Per-cohort state, keyed by cohortId. */
|
|
817
844
|
#cohortStates = /* @__PURE__ */ new Map();
|
|
818
|
-
constructor({ did,
|
|
845
|
+
constructor({ did, publicKey, maxUpdateSizeBytes }) {
|
|
819
846
|
this.did = did;
|
|
820
|
-
this.
|
|
847
|
+
this.publicKey = publicKey;
|
|
821
848
|
this.maxUpdateSizeBytes = maxUpdateSizeBytes ?? DEFAULT_MAX_UPDATE_SIZE_BYTES;
|
|
822
849
|
}
|
|
823
850
|
receive(message) {
|
|
@@ -910,7 +937,7 @@ var AggregationService = class {
|
|
|
910
937
|
cohortSize: state.config.minParticipants,
|
|
911
938
|
beaconType: state.config.beaconType,
|
|
912
939
|
network: state.config.network,
|
|
913
|
-
communicationPk: this.
|
|
940
|
+
communicationPk: this.publicKey.compressed
|
|
914
941
|
});
|
|
915
942
|
state.phase = "Advertised" /* Advertised */;
|
|
916
943
|
return [message];
|
|
@@ -1322,12 +1349,17 @@ var import_utils3 = require("@noble/hashes/utils");
|
|
|
1322
1349
|
var import_btc_signer3 = require("@scure/btc-signer");
|
|
1323
1350
|
var AggregationParticipant = class {
|
|
1324
1351
|
did;
|
|
1325
|
-
|
|
1352
|
+
/** MuSig2 signing capability. The raw secret never lives as a field here. */
|
|
1353
|
+
#signer;
|
|
1326
1354
|
/** Per-cohort state, keyed by cohortId. */
|
|
1327
1355
|
#cohortStates = /* @__PURE__ */ new Map();
|
|
1328
|
-
constructor({ did,
|
|
1356
|
+
constructor({ did, signer }) {
|
|
1329
1357
|
this.did = did;
|
|
1330
|
-
this
|
|
1358
|
+
this.#signer = signer;
|
|
1359
|
+
}
|
|
1360
|
+
/** The participant's compressed (33-byte) MuSig2 public key. Not secret. */
|
|
1361
|
+
get publicKey() {
|
|
1362
|
+
return this.#signer.publicKey;
|
|
1331
1363
|
}
|
|
1332
1364
|
/**
|
|
1333
1365
|
* Process an incoming message. Updates internal state but never produces
|
|
@@ -1416,8 +1448,8 @@ var AggregationParticipant = class {
|
|
|
1416
1448
|
from: this.did,
|
|
1417
1449
|
to: state.serviceDid,
|
|
1418
1450
|
cohortId,
|
|
1419
|
-
participantPk: this.
|
|
1420
|
-
communicationPk: this.
|
|
1451
|
+
participantPk: this.publicKey,
|
|
1452
|
+
communicationPk: this.publicKey
|
|
1421
1453
|
});
|
|
1422
1454
|
return [optInMessage];
|
|
1423
1455
|
}
|
|
@@ -1448,7 +1480,7 @@ var AggregationParticipant = class {
|
|
|
1448
1480
|
const beaconAddress = message.body?.beaconAddress;
|
|
1449
1481
|
const cohortKeys = message.body?.cohortKeys;
|
|
1450
1482
|
if (!beaconAddress || !cohortKeys) return;
|
|
1451
|
-
const participantPkHex = (0, import_utils3.bytesToHex)(this.
|
|
1483
|
+
const participantPkHex = (0, import_utils3.bytesToHex)(this.publicKey);
|
|
1452
1484
|
const cohortKeysHex = cohortKeys.map((k) => (0, import_utils3.bytesToHex)(new Uint8Array(k)));
|
|
1453
1485
|
state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
|
|
1454
1486
|
state.phase = "CohortReady" /* CohortReady */;
|
|
@@ -1615,9 +1647,8 @@ var AggregationParticipant = class {
|
|
|
1615
1647
|
prevOutValues
|
|
1616
1648
|
});
|
|
1617
1649
|
state.signingSession = session;
|
|
1618
|
-
const nonceContribution =
|
|
1619
|
-
this.
|
|
1620
|
-
this.keys.secretKey.bytes
|
|
1650
|
+
const nonceContribution = this.#signer.withSecret(
|
|
1651
|
+
(secretKey) => session.generateNonceContribution(this.publicKey, secretKey)
|
|
1621
1652
|
);
|
|
1622
1653
|
state.phase = "NonceSent" /* NonceSent */;
|
|
1623
1654
|
return [createNonceContributionMessage({
|
|
@@ -1660,7 +1691,10 @@ var AggregationParticipant = class {
|
|
|
1660
1691
|
{ cohortId }
|
|
1661
1692
|
);
|
|
1662
1693
|
}
|
|
1663
|
-
const
|
|
1694
|
+
const signingSession = state.signingSession;
|
|
1695
|
+
const partialSig = this.#signer.withSecret(
|
|
1696
|
+
(secretKey) => signingSession.generatePartialSignature(secretKey)
|
|
1697
|
+
);
|
|
1664
1698
|
state.phase = "Complete" /* Complete */;
|
|
1665
1699
|
return [createSignatureAuthorizationMessage({
|
|
1666
1700
|
from: this.did,
|
|
@@ -1673,6 +1707,37 @@ var AggregationParticipant = class {
|
|
|
1673
1707
|
getCohortPhase(cohortId) {
|
|
1674
1708
|
return this.#cohortStates.get(cohortId)?.phase;
|
|
1675
1709
|
}
|
|
1710
|
+
/**
|
|
1711
|
+
* Zeroize any retained MuSig2 secret nonces across all cohorts. The raw
|
|
1712
|
+
* signing key is never held here (it lives behind the {@link AggregationSigner}
|
|
1713
|
+
* and is wiped per-operation), but an abandoned signing session can still hold
|
|
1714
|
+
* a secret nonce; call this on teardown to clear it deterministically.
|
|
1715
|
+
*/
|
|
1716
|
+
clearSecrets() {
|
|
1717
|
+
for (const state of this.#cohortStates.values()) {
|
|
1718
|
+
state.signingSession?.clearSecrets();
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
|
|
1723
|
+
// src/core/aggregation/signer.ts
|
|
1724
|
+
var import_keypair2 = require("@did-btcr2/keypair");
|
|
1725
|
+
var KeyPairAggregationSigner = class {
|
|
1726
|
+
publicKey;
|
|
1727
|
+
#keys;
|
|
1728
|
+
/** @param {SchnorrKeyPair} keys The keypair whose secret backs this signer. */
|
|
1729
|
+
constructor(keys) {
|
|
1730
|
+
this.#keys = keys;
|
|
1731
|
+
this.publicKey = keys.publicKey.compressed;
|
|
1732
|
+
}
|
|
1733
|
+
withSecret(fn) {
|
|
1734
|
+
const secretKey = this.#keys.secretKey.bytes;
|
|
1735
|
+
try {
|
|
1736
|
+
return fn(secretKey);
|
|
1737
|
+
} finally {
|
|
1738
|
+
(0, import_keypair2.wipe)(secretKey);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1676
1741
|
};
|
|
1677
1742
|
|
|
1678
1743
|
// src/core/aggregation/logger.ts
|
|
@@ -1784,11 +1849,11 @@ var TransportAdapterError = class extends import_common6.MethodError {
|
|
|
1784
1849
|
var import_common10 = require("@did-btcr2/common");
|
|
1785
1850
|
|
|
1786
1851
|
// src/core/aggregation/transport/http/client.ts
|
|
1787
|
-
var
|
|
1852
|
+
var import_keypair4 = require("@did-btcr2/keypair");
|
|
1788
1853
|
|
|
1789
1854
|
// src/core/identifier.ts
|
|
1790
1855
|
var import_common7 = require("@did-btcr2/common");
|
|
1791
|
-
var
|
|
1856
|
+
var import_keypair3 = require("@did-btcr2/keypair");
|
|
1792
1857
|
var import_base4 = require("@scure/base");
|
|
1793
1858
|
var Identifier = class _Identifier {
|
|
1794
1859
|
/**
|
|
@@ -1821,7 +1886,7 @@ var Identifier = class _Identifier {
|
|
|
1821
1886
|
}
|
|
1822
1887
|
if (idType === "KEY") {
|
|
1823
1888
|
try {
|
|
1824
|
-
new
|
|
1889
|
+
new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
|
|
1825
1890
|
} catch {
|
|
1826
1891
|
throw new import_common7.IdentifierError(
|
|
1827
1892
|
'Expected "genesisBytes" to be a valid compressed secp256k1 public key',
|
|
@@ -1923,7 +1988,7 @@ var Identifier = class _Identifier {
|
|
|
1923
1988
|
const genesisBytes = dataBytes.slice(byteIndex + 1);
|
|
1924
1989
|
if (idType === "KEY") {
|
|
1925
1990
|
try {
|
|
1926
|
-
new
|
|
1991
|
+
new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
|
|
1927
1992
|
} catch {
|
|
1928
1993
|
throw new import_common7.IdentifierError(`Invalid genesisBytes: ${genesisBytes}`, import_common7.INVALID_DID, { identifier });
|
|
1929
1994
|
}
|
|
@@ -1935,7 +2000,7 @@ var Identifier = class _Identifier {
|
|
|
1935
2000
|
* @returns {string} The new did:btcr2 identifier.
|
|
1936
2001
|
*/
|
|
1937
2002
|
static generate() {
|
|
1938
|
-
const keyPair =
|
|
2003
|
+
const keyPair = import_keypair3.SchnorrKeyPair.generate();
|
|
1939
2004
|
const did = this.encode(
|
|
1940
2005
|
keyPair.publicKey.compressed,
|
|
1941
2006
|
{
|
|
@@ -1961,7 +2026,7 @@ var Identifier = class _Identifier {
|
|
|
1961
2026
|
{ did, idType }
|
|
1962
2027
|
);
|
|
1963
2028
|
}
|
|
1964
|
-
return new
|
|
2029
|
+
return new import_keypair3.CompressedSecp256k1PublicKey(genesisBytes);
|
|
1965
2030
|
}
|
|
1966
2031
|
/**
|
|
1967
2032
|
* Validates a did:btcr2 identifier.
|
|
@@ -2368,7 +2433,7 @@ var HttpClientTransport = class {
|
|
|
2368
2433
|
}
|
|
2369
2434
|
registerPeer(did, communicationPk) {
|
|
2370
2435
|
try {
|
|
2371
|
-
new
|
|
2436
|
+
new import_keypair4.CompressedSecp256k1PublicKey(communicationPk);
|
|
2372
2437
|
} catch {
|
|
2373
2438
|
throw new HttpTransportError(
|
|
2374
2439
|
`Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
|
|
@@ -2564,14 +2629,14 @@ var HttpClientTransport = class {
|
|
|
2564
2629
|
const peerBytes = this.#peers.get(did);
|
|
2565
2630
|
if (peerBytes) {
|
|
2566
2631
|
try {
|
|
2567
|
-
return new
|
|
2632
|
+
return new import_keypair4.CompressedSecp256k1PublicKey(peerBytes);
|
|
2568
2633
|
} catch {
|
|
2569
2634
|
}
|
|
2570
2635
|
}
|
|
2571
2636
|
try {
|
|
2572
2637
|
const components = Identifier.decode(did);
|
|
2573
2638
|
if (components.idType === "KEY") {
|
|
2574
|
-
return new
|
|
2639
|
+
return new import_keypair4.CompressedSecp256k1PublicKey(components.genesisBytes);
|
|
2575
2640
|
}
|
|
2576
2641
|
} catch {
|
|
2577
2642
|
}
|
|
@@ -2616,7 +2681,7 @@ function flattenMessage(msg) {
|
|
|
2616
2681
|
}
|
|
2617
2682
|
|
|
2618
2683
|
// src/core/aggregation/transport/http/server.ts
|
|
2619
|
-
var
|
|
2684
|
+
var import_keypair5 = require("@did-btcr2/keypair");
|
|
2620
2685
|
|
|
2621
2686
|
// src/core/aggregation/transport/http/inbox-buffer.ts
|
|
2622
2687
|
var InboxBuffer = class {
|
|
@@ -2781,7 +2846,7 @@ var HttpServerTransport = class {
|
|
|
2781
2846
|
}
|
|
2782
2847
|
registerPeer(did, communicationPk) {
|
|
2783
2848
|
try {
|
|
2784
|
-
new
|
|
2849
|
+
new import_keypair5.CompressedSecp256k1PublicKey(communicationPk);
|
|
2785
2850
|
} catch {
|
|
2786
2851
|
throw new HttpTransportError(
|
|
2787
2852
|
`Invalid peer public key for ${did}`,
|
|
@@ -3059,14 +3124,14 @@ var HttpServerTransport = class {
|
|
|
3059
3124
|
const peerBytes = this.#peers.get(did);
|
|
3060
3125
|
if (peerBytes) {
|
|
3061
3126
|
try {
|
|
3062
|
-
return new
|
|
3127
|
+
return new import_keypair5.CompressedSecp256k1PublicKey(peerBytes);
|
|
3063
3128
|
} catch {
|
|
3064
3129
|
}
|
|
3065
3130
|
}
|
|
3066
3131
|
try {
|
|
3067
3132
|
const components = Identifier.decode(did);
|
|
3068
3133
|
if (components.idType === "KEY") {
|
|
3069
|
-
return new
|
|
3134
|
+
return new import_keypair5.CompressedSecp256k1PublicKey(components.genesisBytes);
|
|
3070
3135
|
}
|
|
3071
3136
|
} catch {
|
|
3072
3137
|
}
|
|
@@ -3165,7 +3230,7 @@ function flattenMessage2(msg) {
|
|
|
3165
3230
|
}
|
|
3166
3231
|
|
|
3167
3232
|
// src/core/aggregation/transport/nostr.ts
|
|
3168
|
-
var
|
|
3233
|
+
var import_keypair6 = require("@did-btcr2/keypair");
|
|
3169
3234
|
var import_utils6 = require("@noble/hashes/utils");
|
|
3170
3235
|
var import_nostr_tools = require("nostr-tools");
|
|
3171
3236
|
var import_pool = require("nostr-tools/pool");
|
|
@@ -3263,7 +3328,7 @@ var NostrTransport = class _NostrTransport {
|
|
|
3263
3328
|
*/
|
|
3264
3329
|
registerPeer(did, communicationPk) {
|
|
3265
3330
|
try {
|
|
3266
|
-
new
|
|
3331
|
+
new import_keypair6.CompressedSecp256k1PublicKey(communicationPk);
|
|
3267
3332
|
} catch {
|
|
3268
3333
|
throw new TransportAdapterError(
|
|
3269
3334
|
`Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
|
|
@@ -3370,7 +3435,7 @@ var NostrTransport = class _NostrTransport {
|
|
|
3370
3435
|
if (to) {
|
|
3371
3436
|
const recipientPkBytes = this.#peerRegistry.get(to);
|
|
3372
3437
|
if (recipientPkBytes) {
|
|
3373
|
-
const recipientPk = new
|
|
3438
|
+
const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
|
|
3374
3439
|
tags.push(["p", (0, import_utils6.bytesToHex)(recipientPk.x)]);
|
|
3375
3440
|
}
|
|
3376
3441
|
}
|
|
@@ -3401,7 +3466,7 @@ var NostrTransport = class _NostrTransport {
|
|
|
3401
3466
|
{ adapter: this.name, did: to }
|
|
3402
3467
|
);
|
|
3403
3468
|
}
|
|
3404
|
-
const recipientPk = new
|
|
3469
|
+
const recipientPk = new import_keypair6.CompressedSecp256k1PublicKey(recipientPkBytes);
|
|
3405
3470
|
const conversationKey = import_nostr_tools.nip44.v2.utils.getConversationKey(
|
|
3406
3471
|
senderKeys.secretKey.bytes,
|
|
3407
3472
|
(0, import_utils6.bytesToHex)(recipientPk.x)
|
|
@@ -3641,6 +3706,119 @@ var TransportFactory = class {
|
|
|
3641
3706
|
}
|
|
3642
3707
|
};
|
|
3643
3708
|
|
|
3709
|
+
// src/core/aggregation/transport/in-memory.ts
|
|
3710
|
+
var import_utils7 = require("@noble/hashes/utils");
|
|
3711
|
+
var InMemoryBus = class {
|
|
3712
|
+
#transports = /* @__PURE__ */ new Set();
|
|
3713
|
+
/** Attach a transport to this bus. Called by the transport's constructor. */
|
|
3714
|
+
register(transport) {
|
|
3715
|
+
this.#transports.add(transport);
|
|
3716
|
+
}
|
|
3717
|
+
/** Detach a transport from this bus. */
|
|
3718
|
+
unregister(transport) {
|
|
3719
|
+
this.#transports.delete(transport);
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Deliver a message. With no `recipient` the message is broadcast to every
|
|
3723
|
+
* actor on the bus; otherwise it is routed to the single transport that owns
|
|
3724
|
+
* the recipient DID.
|
|
3725
|
+
*/
|
|
3726
|
+
async deliver(message, _sender, recipient) {
|
|
3727
|
+
const type = message.type;
|
|
3728
|
+
if (!type) return;
|
|
3729
|
+
const replacer = (_k, v) => v instanceof Uint8Array ? { __bytes: (0, import_utils7.bytesToHex)(v) } : v;
|
|
3730
|
+
const reviver = (_k, v) => v && typeof v === "object" && "__bytes" in v ? (0, import_utils7.hexToBytes)(v.__bytes) : v;
|
|
3731
|
+
const raw = JSON.parse(JSON.stringify(message, replacer), reviver);
|
|
3732
|
+
const serialized = { ...raw, ...raw.body ?? {} };
|
|
3733
|
+
if (!recipient) {
|
|
3734
|
+
for (const t of this.#transports) {
|
|
3735
|
+
await t.dispatchBroadcast(type, serialized);
|
|
3736
|
+
}
|
|
3737
|
+
return;
|
|
3738
|
+
}
|
|
3739
|
+
for (const t of this.#transports) {
|
|
3740
|
+
if (t.hasActor(recipient)) {
|
|
3741
|
+
await t.dispatchDirected(recipient, type, serialized);
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
};
|
|
3747
|
+
var InMemoryTransport = class {
|
|
3748
|
+
name = "in-memory";
|
|
3749
|
+
bus;
|
|
3750
|
+
#actors = /* @__PURE__ */ new Map();
|
|
3751
|
+
#peers = /* @__PURE__ */ new Map();
|
|
3752
|
+
/** @param bus Shared bus. Pass the same bus to connect multiple transports. */
|
|
3753
|
+
constructor(bus = new InMemoryBus()) {
|
|
3754
|
+
this.bus = bus;
|
|
3755
|
+
this.bus.register(this);
|
|
3756
|
+
}
|
|
3757
|
+
start() {
|
|
3758
|
+
}
|
|
3759
|
+
registerActor(did, keys) {
|
|
3760
|
+
this.#actors.set(did, { publicKey: keys.publicKey.compressed, handlers: /* @__PURE__ */ new Map() });
|
|
3761
|
+
}
|
|
3762
|
+
getActorPk(did) {
|
|
3763
|
+
return this.#actors.get(did)?.publicKey;
|
|
3764
|
+
}
|
|
3765
|
+
/** True if `did` is registered on this transport. Used by the bus for routing. */
|
|
3766
|
+
hasActor(did) {
|
|
3767
|
+
return this.#actors.has(did);
|
|
3768
|
+
}
|
|
3769
|
+
registerPeer(did, communicationPk) {
|
|
3770
|
+
this.#peers.set(did, communicationPk);
|
|
3771
|
+
}
|
|
3772
|
+
getPeerPk(did) {
|
|
3773
|
+
return this.#peers.get(did);
|
|
3774
|
+
}
|
|
3775
|
+
registerMessageHandler(actorDid, messageType, handler) {
|
|
3776
|
+
const actor = this.#actors.get(actorDid);
|
|
3777
|
+
if (actor) actor.handlers.set(messageType, handler);
|
|
3778
|
+
}
|
|
3779
|
+
unregisterMessageHandler(actorDid, messageType) {
|
|
3780
|
+
const actor = this.#actors.get(actorDid);
|
|
3781
|
+
if (actor) actor.handlers.delete(messageType);
|
|
3782
|
+
}
|
|
3783
|
+
unregisterActor(did) {
|
|
3784
|
+
const actor = this.#actors.get(did);
|
|
3785
|
+
if (!actor) return;
|
|
3786
|
+
actor.handlers.clear();
|
|
3787
|
+
this.#actors.delete(did);
|
|
3788
|
+
this.#peers.delete(did);
|
|
3789
|
+
}
|
|
3790
|
+
async sendMessage(message, sender, recipient) {
|
|
3791
|
+
await this.bus.deliver(message, sender, recipient);
|
|
3792
|
+
}
|
|
3793
|
+
publishRepeating(message, sender, intervalMs, recipient) {
|
|
3794
|
+
let stopped = false;
|
|
3795
|
+
void this.sendMessage(message, sender, recipient).catch(() => {
|
|
3796
|
+
});
|
|
3797
|
+
const timer = setInterval(() => {
|
|
3798
|
+
if (stopped) return;
|
|
3799
|
+
void this.sendMessage(message, sender, recipient).catch(() => {
|
|
3800
|
+
});
|
|
3801
|
+
}, intervalMs);
|
|
3802
|
+
return () => {
|
|
3803
|
+
if (stopped) return;
|
|
3804
|
+
stopped = true;
|
|
3805
|
+
clearInterval(timer);
|
|
3806
|
+
};
|
|
3807
|
+
}
|
|
3808
|
+
/** Deliver a broadcast message to every actor on this transport that handles `type`. */
|
|
3809
|
+
async dispatchBroadcast(type, message) {
|
|
3810
|
+
for (const actor of this.#actors.values()) {
|
|
3811
|
+
const handler = actor.handlers.get(type);
|
|
3812
|
+
if (handler) await handler(message);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
/** Deliver a directed message to the recipient actor's handler for `type`. */
|
|
3816
|
+
async dispatchDirected(recipientDid, type, message) {
|
|
3817
|
+
const handler = this.#actors.get(recipientDid)?.handlers.get(type);
|
|
3818
|
+
if (handler) await handler(message);
|
|
3819
|
+
}
|
|
3820
|
+
};
|
|
3821
|
+
|
|
3644
3822
|
// src/core/aggregation/transport/didcomm.ts
|
|
3645
3823
|
var import_common11 = require("@did-btcr2/common");
|
|
3646
3824
|
var DidCommTransport = class {
|
|
@@ -3793,8 +3971,11 @@ var AggregationServiceRunner = class _AggregationServiceRunner extends TypedEven
|
|
|
3793
3971
|
this.#phaseTimeoutMs = options.phaseTimeoutMs;
|
|
3794
3972
|
this.#advertRepeatIntervalMs = options.advertRepeatIntervalMs ?? DEFAULT_ADVERT_REPEAT_INTERVAL_MS;
|
|
3795
3973
|
this.session = new AggregationService({
|
|
3974
|
+
// The coordinator never signs, so the state machine receives only the
|
|
3975
|
+
// public half of the operator's keypair (see ADR 038). The full keypair
|
|
3976
|
+
// remains the operator's transport/communication identity.
|
|
3796
3977
|
did: options.did,
|
|
3797
|
-
|
|
3978
|
+
publicKey: options.keys.publicKey,
|
|
3798
3979
|
maxUpdateSizeBytes: options.maxUpdateSizeBytes
|
|
3799
3980
|
});
|
|
3800
3981
|
}
|
|
@@ -4146,7 +4327,10 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
|
|
|
4146
4327
|
this.#onProvideUpdate = options.onProvideUpdate;
|
|
4147
4328
|
this.#onValidateData = options.onValidateData ?? (async (info) => ({ approved: info.matches }));
|
|
4148
4329
|
this.#onApproveSigning = options.onApproveSigning ?? (async () => ({ approved: true }));
|
|
4149
|
-
this.session = new AggregationParticipant({
|
|
4330
|
+
this.session = new AggregationParticipant({
|
|
4331
|
+
did: options.did,
|
|
4332
|
+
signer: new KeyPairAggregationSigner(options.keys)
|
|
4333
|
+
});
|
|
4150
4334
|
}
|
|
4151
4335
|
/**
|
|
4152
4336
|
* Start listening for cohorts. The runner stays active until {@link stop}
|
|
@@ -4159,6 +4343,7 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
|
|
|
4159
4343
|
stop() {
|
|
4160
4344
|
this.#stopped = true;
|
|
4161
4345
|
this.#unregisterHandlers();
|
|
4346
|
+
this.session.clearSecrets();
|
|
4162
4347
|
}
|
|
4163
4348
|
/** Message types this runner listens for on the transport. */
|
|
4164
4349
|
static #HANDLED_MESSAGE_TYPES = [
|
|
@@ -4368,8 +4553,64 @@ var AggregationParticipantRunner = class _AggregationParticipantRunner extends T
|
|
|
4368
4553
|
}
|
|
4369
4554
|
};
|
|
4370
4555
|
|
|
4556
|
+
// src/core/aggregation/runner/aggregation-runner.ts
|
|
4557
|
+
var AggregationRunner = class {
|
|
4558
|
+
/**
|
|
4559
|
+
* Run a cohort of ONE participant entirely in-process and return the
|
|
4560
|
+
* aggregated MuSig2 result.
|
|
4561
|
+
*
|
|
4562
|
+
* One party plays both the coordinating service and the lone participant,
|
|
4563
|
+
* connected over an {@link InMemoryTransport} (no relay or HTTP server). This
|
|
4564
|
+
* makes the single-participant aggregate-beacon path — the N=1 corner of the
|
|
4565
|
+
* two-axis beacon matrix (see ADR 037) — first-class, useful for generating
|
|
4566
|
+
* and reproducing single-participant aggregate test vectors.
|
|
4567
|
+
*
|
|
4568
|
+
* The service advertises a cohort with `minParticipants: 1`; the participant
|
|
4569
|
+
* joins, submits its update, and the two complete keygen, data distribution,
|
|
4570
|
+
* validation, and a one-signer MuSig2 P2TR key-path signing round.
|
|
4571
|
+
*
|
|
4572
|
+
* @param options Service + participant identities, cohort config, and the
|
|
4573
|
+
* update / tx-data callbacks.
|
|
4574
|
+
* @returns The {@link AggregationResult} (cohort id, aggregated signature, signed tx).
|
|
4575
|
+
*/
|
|
4576
|
+
static async solo(options) {
|
|
4577
|
+
const transport = new InMemoryTransport(new InMemoryBus());
|
|
4578
|
+
transport.registerActor(options.service.did, options.service.keys);
|
|
4579
|
+
transport.registerActor(options.participant.did, options.participant.keys);
|
|
4580
|
+
transport.registerPeer(options.participant.did, options.participant.keys.publicKey.compressed);
|
|
4581
|
+
transport.registerPeer(options.service.did, options.service.keys.publicKey.compressed);
|
|
4582
|
+
transport.start();
|
|
4583
|
+
const service = new AggregationServiceRunner({
|
|
4584
|
+
transport,
|
|
4585
|
+
did: options.service.did,
|
|
4586
|
+
keys: options.service.keys,
|
|
4587
|
+
config: { minParticipants: 1, network: options.config.network, beaconType: options.config.beaconType },
|
|
4588
|
+
onProvideTxData: options.onProvideTxData,
|
|
4589
|
+
cohortTtlMs: options.cohortTtlMs,
|
|
4590
|
+
phaseTimeoutMs: options.phaseTimeoutMs,
|
|
4591
|
+
// In-process bus with the participant already listening: a single advert
|
|
4592
|
+
// suffices, so disable the republish loop (no dangling interval).
|
|
4593
|
+
advertRepeatIntervalMs: 0
|
|
4594
|
+
});
|
|
4595
|
+
const participant = new AggregationParticipantRunner({
|
|
4596
|
+
transport,
|
|
4597
|
+
did: options.participant.did,
|
|
4598
|
+
keys: options.participant.keys,
|
|
4599
|
+
shouldJoin: async () => true,
|
|
4600
|
+
onProvideUpdate: options.onProvideUpdate
|
|
4601
|
+
});
|
|
4602
|
+
await participant.start();
|
|
4603
|
+
try {
|
|
4604
|
+
return await service.run();
|
|
4605
|
+
} finally {
|
|
4606
|
+
participant.stop();
|
|
4607
|
+
service.stop();
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
};
|
|
4611
|
+
|
|
4371
4612
|
// src/core/beacon/beacon.ts
|
|
4372
|
-
var
|
|
4613
|
+
var import_utils8 = require("@noble/hashes/utils.js");
|
|
4373
4614
|
var import_btc_signer4 = require("@scure/btc-signer");
|
|
4374
4615
|
|
|
4375
4616
|
// src/core/beacon/error.ts
|
|
@@ -4467,7 +4708,7 @@ async function fetchSpendableUtxo(bitcoinAddress, bitcoin) {
|
|
|
4467
4708
|
);
|
|
4468
4709
|
}
|
|
4469
4710
|
const prevTxHex = await bitcoin.rest.transaction.getHex(utxo.txid);
|
|
4470
|
-
return { utxo, prevTxBytes: (0,
|
|
4711
|
+
return { utxo, prevTxBytes: (0, import_utils8.hexToBytes)(prevTxHex) };
|
|
4471
4712
|
}
|
|
4472
4713
|
async function buildAggregationBeaconTx(opts) {
|
|
4473
4714
|
const feeEstimator = opts.feeEstimator ?? DEFAULT_FEE_ESTIMATOR;
|
|
@@ -4508,7 +4749,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
|
|
|
4508
4749
|
const sighashType = import_btc_signer4.SigHash.ALL;
|
|
4509
4750
|
const sighash2 = tx.preimageLegacy(inputIdx, prevOutScript, sighashType);
|
|
4510
4751
|
const sig2 = signer.sign(sighash2, "ecdsa");
|
|
4511
|
-
const sigWithType = (0,
|
|
4752
|
+
const sigWithType = (0, import_utils8.concatBytes)(sig2, new Uint8Array([sighashType]));
|
|
4512
4753
|
tx.updateInput(inputIdx, { partialSig: [[pubkey, sigWithType]] }, true);
|
|
4513
4754
|
tx.finalize();
|
|
4514
4755
|
return tx.hex;
|
|
@@ -4526,7 +4767,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
|
|
|
4526
4767
|
const sighashType = import_btc_signer4.SigHash.ALL;
|
|
4527
4768
|
const sighash2 = tx.preimageWitnessV0(inputIdx, sighashScript, sighashType, amount);
|
|
4528
4769
|
const sig2 = signer.sign(sighash2, "ecdsa");
|
|
4529
|
-
const sigWithType = (0,
|
|
4770
|
+
const sigWithType = (0, import_utils8.concatBytes)(sig2, new Uint8Array([sighashType]));
|
|
4530
4771
|
tx.updateInput(inputIdx, { partialSig: [[pubkey, sigWithType]] }, true);
|
|
4531
4772
|
tx.finalize();
|
|
4532
4773
|
return tx.hex;
|
|
@@ -4537,7 +4778,7 @@ async function signSingletonInput(tx, inputIdx, kind, signer, prevOutScript, amo
|
|
|
4537
4778
|
tx.finalize();
|
|
4538
4779
|
return tx.hex;
|
|
4539
4780
|
}
|
|
4540
|
-
var
|
|
4781
|
+
var SinglePartyBeacon = class {
|
|
4541
4782
|
/**
|
|
4542
4783
|
* The Beacon service configuration parsed from the DID Document.
|
|
4543
4784
|
*/
|
|
@@ -4674,7 +4915,7 @@ var Beacon = class {
|
|
|
4674
4915
|
|
|
4675
4916
|
// src/core/beacon/cas-beacon.ts
|
|
4676
4917
|
var import_common13 = require("@did-btcr2/common");
|
|
4677
|
-
var CASBeacon = class extends
|
|
4918
|
+
var CASBeacon = class extends SinglePartyBeacon {
|
|
4678
4919
|
/**
|
|
4679
4920
|
* Creates an instance of CASBeacon.
|
|
4680
4921
|
* @param {BeaconService} service The service of the Beacon.
|
|
@@ -4734,7 +4975,7 @@ var CASBeacon = class extends Beacon {
|
|
|
4734
4975
|
* Creates a CAS Announcement mapping the DID to the update hash, broadcasts the hash of the
|
|
4735
4976
|
* announcement via OP_RETURN, and optionally publishes the announcement off-chain via the
|
|
4736
4977
|
* supplied `casPublish` callback. UTXO selection, PSBT construction, fee estimation, signing,
|
|
4737
|
-
* and broadcast are delegated to {@link
|
|
4978
|
+
* and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
|
|
4738
4979
|
*
|
|
4739
4980
|
* @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
|
|
4740
4981
|
* @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
|
|
@@ -4762,7 +5003,7 @@ var import_common16 = require("@did-btcr2/common");
|
|
|
4762
5003
|
|
|
4763
5004
|
// src/core/beacon/singleton-beacon.ts
|
|
4764
5005
|
var import_common14 = require("@did-btcr2/common");
|
|
4765
|
-
var SingletonBeacon = class extends
|
|
5006
|
+
var SingletonBeacon = class extends SinglePartyBeacon {
|
|
4766
5007
|
/**
|
|
4767
5008
|
* Creates an instance of SingletonBeacon.
|
|
4768
5009
|
* @param {BeaconService} service The BeaconService object representing the funded beacon to announce the update to.
|
|
@@ -4799,7 +5040,7 @@ var SingletonBeacon = class extends Beacon {
|
|
|
4799
5040
|
*
|
|
4800
5041
|
* The signal bytes embedded in OP_RETURN are the SHA-256 canonical hash of the signed update.
|
|
4801
5042
|
* UTXO selection, PSBT construction, fee estimation, signing, and broadcast are delegated to
|
|
4802
|
-
* {@link
|
|
5043
|
+
* {@link SinglePartyBeacon.buildSignAndBroadcast}.
|
|
4803
5044
|
*
|
|
4804
5045
|
* @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
|
|
4805
5046
|
* @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
|
|
@@ -4818,8 +5059,8 @@ var SingletonBeacon = class extends Beacon {
|
|
|
4818
5059
|
// src/core/beacon/smt-beacon.ts
|
|
4819
5060
|
var import_common15 = require("@did-btcr2/common");
|
|
4820
5061
|
var import_smt3 = require("@did-btcr2/smt");
|
|
4821
|
-
var
|
|
4822
|
-
var SMTBeacon = class extends
|
|
5062
|
+
var import_utils9 = require("@noble/hashes/utils");
|
|
5063
|
+
var SMTBeacon = class extends SinglePartyBeacon {
|
|
4823
5064
|
/**
|
|
4824
5065
|
* Creates an instance of SMTBeacon.
|
|
4825
5066
|
* @param {BeaconService} service The Beacon service.
|
|
@@ -4895,7 +5136,7 @@ var SMTBeacon = class extends Beacon {
|
|
|
4895
5136
|
* Builds a single-entry Sparse Merkle Tree from the signed update, then broadcasts the tree's
|
|
4896
5137
|
* root hash via OP_RETURN. For multi-party aggregation, use the {@link AggregationService}
|
|
4897
5138
|
* subsystem directly instead of this method. UTXO selection, PSBT construction, fee estimation,
|
|
4898
|
-
* signing, and broadcast are delegated to {@link
|
|
5139
|
+
* signing, and broadcast are delegated to {@link SinglePartyBeacon.buildSignAndBroadcast}.
|
|
4899
5140
|
*
|
|
4900
5141
|
* @param {SignedBTCR2Update} signedUpdate The signed BTCR2 update to broadcast.
|
|
4901
5142
|
* @param {Signer} signer Signer that produces the ECDSA signature for the Bitcoin transaction.
|
|
@@ -4907,7 +5148,7 @@ var SMTBeacon = class extends Beacon {
|
|
|
4907
5148
|
async broadcastSignal(signedUpdate, signer, bitcoin, options) {
|
|
4908
5149
|
const did = this.service.id.split("#")[0];
|
|
4909
5150
|
const canonicalBytes = new TextEncoder().encode((0, import_common15.canonicalize)(signedUpdate));
|
|
4910
|
-
const nonce = (0,
|
|
5151
|
+
const nonce = (0, import_utils9.randomBytes)(32);
|
|
4911
5152
|
const tree = new import_smt3.BTCR2MerkleTree();
|
|
4912
5153
|
tree.addEntries([{ did, nonce, signedUpdate: canonicalBytes }]);
|
|
4913
5154
|
tree.finalize();
|
|
@@ -4921,7 +5162,7 @@ var BeaconFactory = class {
|
|
|
4921
5162
|
/**
|
|
4922
5163
|
* Establish a Beacon instance based on the provided service and optional sidecar data.
|
|
4923
5164
|
* @param {BeaconService} service The beacon service configuration.
|
|
4924
|
-
* @returns {
|
|
5165
|
+
* @returns {SinglePartyBeacon} The established Beacon instance.
|
|
4925
5166
|
*/
|
|
4926
5167
|
static establish(service) {
|
|
4927
5168
|
switch (service.type) {
|
|
@@ -4938,11 +5179,11 @@ var BeaconFactory = class {
|
|
|
4938
5179
|
};
|
|
4939
5180
|
|
|
4940
5181
|
// src/core/beacon/signal-discovery.ts
|
|
4941
|
-
var
|
|
5182
|
+
var import_bitcoin3 = require("@did-btcr2/bitcoin");
|
|
4942
5183
|
var import_common18 = require("@did-btcr2/common");
|
|
4943
5184
|
|
|
4944
5185
|
// src/core/beacon/utils.ts
|
|
4945
|
-
var
|
|
5186
|
+
var import_bitcoin2 = require("@did-btcr2/bitcoin");
|
|
4946
5187
|
var import_common17 = require("@did-btcr2/common");
|
|
4947
5188
|
var import_btc_signer5 = require("@scure/btc-signer");
|
|
4948
5189
|
|
|
@@ -6049,7 +6290,7 @@ var BeaconUtils = class {
|
|
|
6049
6290
|
static createBeaconService(did, addressType, beaconType) {
|
|
6050
6291
|
try {
|
|
6051
6292
|
const components = Identifier.decode(did);
|
|
6052
|
-
const network = (0,
|
|
6293
|
+
const network = (0, import_bitcoin2.getNetwork)(components.network);
|
|
6053
6294
|
const pubkey = components.genesisBytes;
|
|
6054
6295
|
const id = `${did}#initial${addressType.toUpperCase()}`;
|
|
6055
6296
|
const address = addressType === "p2tr" ? (0, import_btc_signer5.p2tr)(pubkey.slice(1, 33), void 0, network).address : addressType === "p2wpkh" ? (0, import_btc_signer5.p2wpkh)(pubkey, network).address : (0, import_btc_signer5.p2pkh)(pubkey, network).address;
|
|
@@ -6200,14 +6441,14 @@ var BeaconSignalDiscovery = class {
|
|
|
6200
6441
|
console.info(`Searching for beacon signals, please wait ...`);
|
|
6201
6442
|
while (block.height <= targetHeight) {
|
|
6202
6443
|
for (const tx of block.tx) {
|
|
6203
|
-
if (tx.txid ===
|
|
6444
|
+
if (tx.txid === import_bitcoin3.GENESIS_TX_ID) {
|
|
6204
6445
|
continue;
|
|
6205
6446
|
}
|
|
6206
6447
|
for (const vin of tx.vin) {
|
|
6207
6448
|
if (vin.coinbase) {
|
|
6208
6449
|
continue;
|
|
6209
6450
|
}
|
|
6210
|
-
if (vin.txinwitness && vin.txinwitness.length === 1 && vin.txinwitness[0] ===
|
|
6451
|
+
if (vin.txinwitness && vin.txinwitness.length === 1 && vin.txinwitness[0] === import_bitcoin3.TXIN_WITNESS_COINBASE) {
|
|
6211
6452
|
continue;
|
|
6212
6453
|
}
|
|
6213
6454
|
if (!vin.txid) {
|
|
@@ -6261,10 +6502,10 @@ var BeaconSignalDiscovery = class {
|
|
|
6261
6502
|
};
|
|
6262
6503
|
|
|
6263
6504
|
// src/core/resolver.ts
|
|
6264
|
-
var
|
|
6505
|
+
var import_bitcoin5 = require("@did-btcr2/bitcoin");
|
|
6265
6506
|
var import_common22 = require("@did-btcr2/common");
|
|
6266
6507
|
var import_cryptosuite3 = require("@did-btcr2/cryptosuite");
|
|
6267
|
-
var
|
|
6508
|
+
var import_keypair8 = require("@did-btcr2/keypair");
|
|
6268
6509
|
|
|
6269
6510
|
// src/did-btcr2.ts
|
|
6270
6511
|
var import_common21 = require("@did-btcr2/common");
|
|
@@ -6275,10 +6516,10 @@ var import_common20 = require("@did-btcr2/common");
|
|
|
6275
6516
|
var import_cryptosuite2 = require("@did-btcr2/cryptosuite");
|
|
6276
6517
|
|
|
6277
6518
|
// src/utils/did-document.ts
|
|
6278
|
-
var
|
|
6519
|
+
var import_bitcoin4 = require("@did-btcr2/bitcoin");
|
|
6279
6520
|
var import_common19 = require("@did-btcr2/common");
|
|
6280
|
-
var
|
|
6281
|
-
var
|
|
6521
|
+
var import_keypair7 = require("@did-btcr2/keypair");
|
|
6522
|
+
var import_utils11 = require("@web5/dids/utils");
|
|
6282
6523
|
var import_btc_signer6 = require("@scure/btc-signer");
|
|
6283
6524
|
var BTCR2_DID_DOCUMENT_CONTEXT = [
|
|
6284
6525
|
"https://www.w3.org/ns/did/v1.1",
|
|
@@ -6488,7 +6729,7 @@ var DidDocument = class _DidDocument {
|
|
|
6488
6729
|
* @returns {boolean} True if the services are valid.
|
|
6489
6730
|
*/
|
|
6490
6731
|
static isValidServices(service) {
|
|
6491
|
-
return Array.isArray(service) && service.every(
|
|
6732
|
+
return Array.isArray(service) && service.every(import_utils11.isDidService);
|
|
6492
6733
|
}
|
|
6493
6734
|
/**
|
|
6494
6735
|
* Validates verification relationships (authentication, assertionMethod, capabilityInvocation, capabilityDelegation).
|
|
@@ -6599,9 +6840,9 @@ var GenesisDocument = class _GenesisDocument extends DidDocument {
|
|
|
6599
6840
|
* @returns {GenesisDocument} A new GenesisDocument with the placeholder ID.
|
|
6600
6841
|
*/
|
|
6601
6842
|
static fromPublicKey(publicKey, network) {
|
|
6602
|
-
const pk = new
|
|
6843
|
+
const pk = new import_keypair7.CompressedSecp256k1PublicKey(publicKey);
|
|
6603
6844
|
const id = ID_PLACEHOLDER_VALUE;
|
|
6604
|
-
const address = (0, import_btc_signer6.p2pkh)(pk.compressed, (0,
|
|
6845
|
+
const address = (0, import_btc_signer6.p2pkh)(pk.compressed, (0, import_bitcoin4.getNetwork)(network)).address;
|
|
6605
6846
|
const services = [{
|
|
6606
6847
|
id: `${id}#service-0`,
|
|
6607
6848
|
serviceEndpoint: `bitcoin:${address}`,
|
|
@@ -7068,7 +7309,7 @@ var DidBtcr2 = class {
|
|
|
7068
7309
|
};
|
|
7069
7310
|
|
|
7070
7311
|
// src/core/resolver.ts
|
|
7071
|
-
var
|
|
7312
|
+
var import_utils13 = require("@noble/curves/utils.js");
|
|
7072
7313
|
var Resolver = class _Resolver {
|
|
7073
7314
|
// --- Immutable inputs ---
|
|
7074
7315
|
#didComponents;
|
|
@@ -7108,11 +7349,11 @@ var Resolver = class _Resolver {
|
|
|
7108
7349
|
static deterministic(didComponents) {
|
|
7109
7350
|
const genesisBytes = didComponents.genesisBytes;
|
|
7110
7351
|
const did = Identifier.encode(genesisBytes, didComponents);
|
|
7111
|
-
const { multibase } = new
|
|
7352
|
+
const { multibase } = new import_keypair8.CompressedSecp256k1PublicKey(genesisBytes);
|
|
7112
7353
|
const service = BeaconUtils.generateBeaconServices({
|
|
7113
7354
|
id: did,
|
|
7114
7355
|
publicKey: genesisBytes,
|
|
7115
|
-
network: (0,
|
|
7356
|
+
network: (0, import_bitcoin5.getNetwork)(didComponents.network),
|
|
7116
7357
|
beaconType: "SingletonBeacon"
|
|
7117
7358
|
});
|
|
7118
7359
|
return new DidDocument({
|
|
@@ -7135,7 +7376,7 @@ var Resolver = class _Resolver {
|
|
|
7135
7376
|
*/
|
|
7136
7377
|
static external(didComponents, genesisDocument) {
|
|
7137
7378
|
const genesisDocumentHash = (0, import_common22.canonicalHashBytes)(genesisDocument);
|
|
7138
|
-
if (!(0,
|
|
7379
|
+
if (!(0, import_utils13.equalBytes)(didComponents.genesisBytes, genesisDocumentHash)) {
|
|
7139
7380
|
throw new import_common22.ResolveError(
|
|
7140
7381
|
`Initial document mismatch: genesisBytes !== genesisDocumentHash`,
|
|
7141
7382
|
import_common22.INVALID_DID_DOCUMENT,
|
|
@@ -7212,7 +7453,7 @@ var Resolver = class _Resolver {
|
|
|
7212
7453
|
this.confirmDuplicate(update, updateHashHistory);
|
|
7213
7454
|
} else if (update.targetVersionId === currentVersionId + 1) {
|
|
7214
7455
|
const sourceHashBytes = (0, import_common22.decode)(update.sourceHash, "base64urlnopad");
|
|
7215
|
-
if (!(0,
|
|
7456
|
+
if (!(0, import_utils13.equalBytes)(sourceHashBytes, currentDocumentHash)) {
|
|
7216
7457
|
throw new import_common22.ResolveError(
|
|
7217
7458
|
`Hash mismatch: update.sourceHash !== currentDocumentHash`,
|
|
7218
7459
|
import_common22.INVALID_DID_UPDATE,
|
|
@@ -7259,7 +7500,7 @@ var Resolver = class _Resolver {
|
|
|
7259
7500
|
const { proof: _, ...unsignedUpdate } = update;
|
|
7260
7501
|
const unsignedUpdateHash = (0, import_common22.canonicalHashBytes)(unsignedUpdate);
|
|
7261
7502
|
const historicalUpdateHash = updateHashHistory[update.targetVersionId - 2];
|
|
7262
|
-
if (!(0,
|
|
7503
|
+
if (!(0, import_utils13.equalBytes)(historicalUpdateHash, unsignedUpdateHash)) {
|
|
7263
7504
|
throw new import_common22.ResolveError(
|
|
7264
7505
|
`Invalid duplicate: unsigned update hash does not match historical hash`,
|
|
7265
7506
|
import_common22.LATE_PUBLISHING_ERROR,
|
|
@@ -7312,7 +7553,7 @@ var Resolver = class _Resolver {
|
|
|
7312
7553
|
DidDocument.validate(updatedDocument);
|
|
7313
7554
|
const currentDocumentHash = (0, import_common22.canonicalHashBytes)(updatedDocument);
|
|
7314
7555
|
const updateTargetHash = (0, import_common22.decode)(update.targetHash);
|
|
7315
|
-
if (!(0,
|
|
7556
|
+
if (!(0, import_utils13.equalBytes)(updateTargetHash, currentDocumentHash)) {
|
|
7316
7557
|
throw new import_common22.ResolveError(
|
|
7317
7558
|
`Invalid update: update.targetHash !== currentDocumentHash`,
|
|
7318
7559
|
import_common22.INVALID_DID_UPDATE,
|
|
@@ -7539,6 +7780,7 @@ var DidDocumentBuilder = class {
|
|
|
7539
7780
|
AggregationParticipant,
|
|
7540
7781
|
AggregationParticipantError,
|
|
7541
7782
|
AggregationParticipantRunner,
|
|
7783
|
+
AggregationRunner,
|
|
7542
7784
|
AggregationService,
|
|
7543
7785
|
AggregationServiceError,
|
|
7544
7786
|
AggregationServiceRunner,
|
|
@@ -7546,7 +7788,6 @@ var DidDocumentBuilder = class {
|
|
|
7546
7788
|
BECH32M_CHARS,
|
|
7547
7789
|
BTCR2_DID_DOCUMENT_CONTEXT,
|
|
7548
7790
|
BaseMessage,
|
|
7549
|
-
Beacon,
|
|
7550
7791
|
BeaconError,
|
|
7551
7792
|
BeaconFactory,
|
|
7552
7793
|
BeaconSignalDiscovery,
|
|
@@ -7581,8 +7822,11 @@ var DidDocumentBuilder = class {
|
|
|
7581
7822
|
HttpTransportError,
|
|
7582
7823
|
ID_PLACEHOLDER_VALUE,
|
|
7583
7824
|
Identifier,
|
|
7825
|
+
InMemoryBus,
|
|
7584
7826
|
InMemoryRateLimitStore,
|
|
7827
|
+
InMemoryTransport,
|
|
7585
7828
|
InboxBuffer,
|
|
7829
|
+
KeyPairAggregationSigner,
|
|
7586
7830
|
NONCE_CONTRIBUTION,
|
|
7587
7831
|
NonceCache,
|
|
7588
7832
|
NostrTransport,
|
|
@@ -7603,6 +7847,7 @@ var DidDocumentBuilder = class {
|
|
|
7603
7847
|
ServiceCohortPhase,
|
|
7604
7848
|
SigningSessionError,
|
|
7605
7849
|
SigningSessionPhase,
|
|
7850
|
+
SinglePartyBeacon,
|
|
7606
7851
|
SingletonBeacon,
|
|
7607
7852
|
SingletonBeaconError,
|
|
7608
7853
|
StaticFeeEstimator,
|