@did-btcr2/method 0.26.0 → 0.27.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/README.md +86 -233
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.js +24111 -20342
- package/dist/browser.mjs +24111 -20342
- package/dist/cjs/index.js +2463 -2174
- package/dist/esm/core/aggregation/cohort.js +178 -0
- package/dist/esm/core/aggregation/cohort.js.map +1 -0
- package/dist/esm/core/aggregation/errors.js +22 -0
- package/dist/esm/core/aggregation/errors.js.map +1 -0
- package/dist/esm/core/{beacon/aggregation/cohort → aggregation}/messages/base.js +0 -1
- package/dist/esm/core/aggregation/messages/base.js.map +1 -0
- package/dist/esm/core/aggregation/messages/constants.js +26 -0
- package/dist/esm/core/aggregation/messages/constants.js.map +1 -0
- package/dist/esm/core/aggregation/messages/factories.js +113 -0
- package/dist/esm/core/aggregation/messages/factories.js.map +1 -0
- package/dist/esm/core/aggregation/messages/guards.js +37 -0
- package/dist/esm/core/aggregation/messages/guards.js.map +1 -0
- package/dist/esm/core/aggregation/messages/index.js +5 -0
- package/dist/esm/core/aggregation/messages/index.js.map +1 -0
- package/dist/esm/core/aggregation/participant.js +376 -0
- package/dist/esm/core/aggregation/participant.js.map +1 -0
- package/dist/esm/core/aggregation/phases.js +39 -0
- package/dist/esm/core/aggregation/phases.js.map +1 -0
- package/dist/esm/core/aggregation/runner/events.js +2 -0
- package/dist/esm/core/aggregation/runner/events.js.map +1 -0
- package/dist/esm/core/aggregation/runner/index.js +5 -0
- package/dist/esm/core/aggregation/runner/index.js.map +1 -0
- package/dist/esm/core/aggregation/runner/participant-runner.js +282 -0
- package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -0
- package/dist/esm/core/aggregation/runner/service-runner.js +290 -0
- package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -0
- package/dist/esm/core/aggregation/runner/typed-emitter.js +80 -0
- package/dist/esm/core/aggregation/runner/typed-emitter.js.map +1 -0
- package/dist/esm/core/aggregation/service.js +416 -0
- package/dist/esm/core/aggregation/service.js.map +1 -0
- package/dist/esm/core/aggregation/signing-session.js +133 -0
- package/dist/esm/core/aggregation/signing-session.js.map +1 -0
- package/dist/esm/core/aggregation/transport/didcomm.js +32 -0
- package/dist/esm/core/aggregation/transport/didcomm.js.map +1 -0
- package/dist/esm/core/aggregation/transport/error.js +12 -0
- package/dist/esm/core/aggregation/transport/error.js.map +1 -0
- package/dist/esm/core/aggregation/transport/factory.js +20 -0
- package/dist/esm/core/aggregation/transport/factory.js.map +1 -0
- package/dist/esm/core/aggregation/transport/index.js +6 -0
- package/dist/esm/core/aggregation/transport/index.js.map +1 -0
- package/dist/esm/core/aggregation/transport/nostr.js +262 -0
- package/dist/esm/core/aggregation/transport/nostr.js.map +1 -0
- package/dist/esm/core/aggregation/transport/transport.js +2 -0
- package/dist/esm/core/aggregation/transport/transport.js.map +1 -0
- package/dist/esm/core/beacon/beacon.js +80 -0
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/cas-beacon.js +15 -56
- package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
- package/dist/esm/core/beacon/error.js +0 -10
- package/dist/esm/core/beacon/error.js.map +1 -1
- package/dist/esm/core/beacon/fee-estimator.js +30 -0
- package/dist/esm/core/beacon/fee-estimator.js.map +1 -0
- package/dist/esm/core/beacon/singleton-beacon.js +10 -53
- package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
- package/dist/esm/core/beacon/smt-beacon.js +85 -9
- package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
- package/dist/esm/core/identifier.js +13 -0
- package/dist/esm/core/identifier.js.map +1 -1
- package/dist/esm/core/resolver.js +9 -0
- package/dist/esm/core/resolver.js.map +1 -1
- package/dist/esm/index.js +14 -24
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/aggregation/cohort.d.ts +94 -0
- package/dist/types/core/aggregation/cohort.d.ts.map +1 -0
- package/dist/types/core/aggregation/errors.d.ts +14 -0
- package/dist/types/core/aggregation/errors.d.ts.map +1 -0
- package/dist/types/core/{beacon/aggregation/cohort → aggregation}/messages/base.d.ts +7 -1
- package/dist/types/core/aggregation/messages/base.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/constants.d.ts +23 -0
- package/dist/types/core/aggregation/messages/constants.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/factories.d.ts +177 -0
- package/dist/types/core/aggregation/messages/factories.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/guards.d.ts +11 -0
- package/dist/types/core/aggregation/messages/guards.d.ts.map +1 -0
- package/dist/types/core/aggregation/messages/index.d.ts +5 -0
- package/dist/types/core/aggregation/messages/index.d.ts.map +1 -0
- package/dist/types/core/aggregation/participant.d.ts +101 -0
- package/dist/types/core/aggregation/participant.d.ts.map +1 -0
- package/dist/types/core/aggregation/phases.d.ts +49 -0
- package/dist/types/core/aggregation/phases.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/events.d.ts +89 -0
- package/dist/types/core/aggregation/runner/events.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/index.d.ts +5 -0
- package/dist/types/core/aggregation/runner/index.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/participant-runner.d.ts +107 -0
- package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/service-runner.d.ts +102 -0
- package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -0
- package/dist/types/core/aggregation/runner/typed-emitter.d.ts +41 -0
- package/dist/types/core/aggregation/runner/typed-emitter.d.ts.map +1 -0
- package/dist/types/core/aggregation/service.d.ts +112 -0
- package/dist/types/core/aggregation/service.d.ts.map +1 -0
- package/dist/types/core/aggregation/signing-session.d.ts +69 -0
- package/dist/types/core/aggregation/signing-session.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/didcomm.d.ts +20 -0
- package/dist/types/core/aggregation/transport/didcomm.d.ts.map +1 -0
- package/dist/types/core/{beacon/aggregation/communication → aggregation/transport}/error.d.ts +2 -2
- package/dist/types/core/aggregation/transport/error.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/factory.d.ts +13 -0
- package/dist/types/core/aggregation/transport/factory.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/index.d.ts +6 -0
- package/dist/types/core/aggregation/transport/index.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/nostr.d.ts +55 -0
- package/dist/types/core/aggregation/transport/nostr.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/transport.d.ts +37 -0
- package/dist/types/core/aggregation/transport/transport.d.ts.map +1 -0
- package/dist/types/core/beacon/beacon.d.ts +37 -2
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/cas-beacon.d.ts +19 -7
- package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/error.d.ts +0 -6
- package/dist/types/core/beacon/error.d.ts.map +1 -1
- package/dist/types/core/beacon/fee-estimator.d.ts +40 -0
- package/dist/types/core/beacon/fee-estimator.d.ts.map +1 -0
- package/dist/types/core/beacon/interfaces.d.ts +8 -0
- package/dist/types/core/beacon/interfaces.d.ts.map +1 -1
- package/dist/types/core/beacon/singleton-beacon.d.ts +9 -2
- package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/smt-beacon.d.ts +27 -7
- package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
- package/dist/types/core/identifier.d.ts +8 -0
- package/dist/types/core/identifier.d.ts.map +1 -1
- package/dist/types/core/interfaces.d.ts +2 -2
- package/dist/types/core/resolver.d.ts +11 -1
- package/dist/types/core/resolver.d.ts.map +1 -1
- package/dist/types/index.d.ts +9 -24
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +31 -30
- package/src/core/aggregation/cohort.ts +247 -0
- package/src/core/aggregation/errors.ts +25 -0
- package/src/core/{beacon/aggregation/cohort → aggregation}/messages/base.ts +8 -3
- package/src/core/aggregation/messages/constants.ts +28 -0
- package/src/core/aggregation/messages/factories.ts +240 -0
- package/src/core/aggregation/messages/guards.ts +55 -0
- package/src/core/aggregation/messages/index.ts +4 -0
- package/src/core/aggregation/participant.ts +510 -0
- package/src/core/aggregation/phases.ts +82 -0
- package/src/core/aggregation/runner/events.ts +77 -0
- package/src/core/aggregation/runner/index.ts +4 -0
- package/src/core/aggregation/runner/participant-runner.ts +360 -0
- package/src/core/aggregation/runner/service-runner.ts +365 -0
- package/src/core/aggregation/runner/typed-emitter.ts +87 -0
- package/src/core/aggregation/service.ts +547 -0
- package/src/core/aggregation/signing-session.ts +209 -0
- package/src/core/aggregation/transport/didcomm.ts +42 -0
- package/src/core/aggregation/transport/error.ts +13 -0
- package/src/core/aggregation/transport/factory.ts +29 -0
- package/src/core/aggregation/transport/index.ts +5 -0
- package/src/core/aggregation/transport/nostr.ts +333 -0
- package/src/core/aggregation/transport/transport.ts +46 -0
- package/src/core/beacon/beacon.ts +122 -2
- package/src/core/beacon/cas-beacon.ts +28 -76
- package/src/core/beacon/error.ts +0 -12
- package/src/core/beacon/fee-estimator.ts +52 -0
- package/src/core/beacon/interfaces.ts +10 -1
- package/src/core/beacon/singleton-beacon.ts +14 -75
- package/src/core/beacon/smt-beacon.ts +109 -11
- package/src/core/identifier.ts +17 -0
- package/src/core/interfaces.ts +2 -2
- package/src/core/resolver.ts +25 -2
- package/src/index.ts +15 -29
- package/dist/esm/core/beacon/aggregation/cohort/index.js +0 -237
- package/dist/esm/core/beacon/aggregation/cohort/index.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/base.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/constants.js +0 -11
- package/dist/esm/core/beacon/aggregation/cohort/messages/constants.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/index.js +0 -98
- package/dist/esm/core/beacon/aggregation/cohort/messages/index.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js +0 -31
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js +0 -29
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js +0 -27
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js +0 -23
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js +0 -28
- package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js +0 -29
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js +0 -30
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js +0 -30
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js +0 -30
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js +0 -31
- package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/cohort/status.js +0 -8
- package/dist/esm/core/beacon/aggregation/cohort/status.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js +0 -121
- package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +0 -245
- package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/communication/error.js +0 -12
- package/dist/esm/core/beacon/aggregation/communication/error.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/communication/factory.js +0 -21
- package/dist/esm/core/beacon/aggregation/communication/factory.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/communication/service.js +0 -2
- package/dist/esm/core/beacon/aggregation/communication/service.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/coordinator.js +0 -343
- package/dist/esm/core/beacon/aggregation/coordinator.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/participant.js +0 -435
- package/dist/esm/core/beacon/aggregation/participant.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/session/index.js +0 -244
- package/dist/esm/core/beacon/aggregation/session/index.js.map +0 -1
- package/dist/esm/core/beacon/aggregation/session/status.js +0 -11
- package/dist/esm/core/beacon/aggregation/session/status.js.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/index.d.ts +0 -136
- package/dist/types/core/beacon/aggregation/cohort/index.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/constants.d.ts +0 -11
- package/dist/types/core/beacon/aggregation/cohort/messages/constants.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/index.d.ts +0 -65
- package/dist/types/core/beacon/aggregation/cohort/messages/index.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts +0 -29
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts +0 -26
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts +0 -24
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts +0 -20
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts +0 -25
- package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts +0 -25
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts +0 -26
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts +0 -26
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts +0 -26
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts +0 -27
- package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/cohort/status.d.ts +0 -8
- package/dist/types/core/beacon/aggregation/cohort/status.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts +0 -89
- package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts +0 -103
- package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/communication/error.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/communication/factory.d.ts +0 -10
- package/dist/types/core/beacon/aggregation/communication/factory.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/communication/service.d.ts +0 -36
- package/dist/types/core/beacon/aggregation/communication/service.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/coordinator.d.ts +0 -116
- package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/participant.d.ts +0 -192
- package/dist/types/core/beacon/aggregation/participant.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/session/index.d.ts +0 -156
- package/dist/types/core/beacon/aggregation/session/index.d.ts.map +0 -1
- package/dist/types/core/beacon/aggregation/session/status.d.ts +0 -11
- package/dist/types/core/beacon/aggregation/session/status.d.ts.map +0 -1
- package/src/core/beacon/aggregation/cohort/index.ts +0 -305
- package/src/core/beacon/aggregation/cohort/messages/constants.ts +0 -12
- package/src/core/beacon/aggregation/cohort/messages/index.ts +0 -143
- package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.ts +0 -44
- package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.ts +0 -40
- package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.ts +0 -35
- package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in.ts +0 -34
- package/src/core/beacon/aggregation/cohort/messages/keygen/subscribe.ts +0 -36
- package/src/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.ts +0 -39
- package/src/core/beacon/aggregation/cohort/messages/sign/authorization-request.ts +0 -40
- package/src/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.ts +0 -40
- package/src/core/beacon/aggregation/cohort/messages/sign/request-signature.ts +0 -40
- package/src/core/beacon/aggregation/cohort/messages/sign/signature-authorization.ts +0 -41
- package/src/core/beacon/aggregation/cohort/status.ts +0 -7
- package/src/core/beacon/aggregation/communication/adapter/did-comm.ts +0 -148
- package/src/core/beacon/aggregation/communication/adapter/nostr.ts +0 -323
- package/src/core/beacon/aggregation/communication/error.ts +0 -13
- package/src/core/beacon/aggregation/communication/factory.ts +0 -25
- package/src/core/beacon/aggregation/communication/service.ts +0 -42
- package/src/core/beacon/aggregation/coordinator.ts +0 -419
- package/src/core/beacon/aggregation/participant.ts +0 -517
- package/src/core/beacon/aggregation/session/index.ts +0 -301
- package/src/core/beacon/aggregation/session/status.ts +0 -18
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import { canonicalHash, canonicalize } from '@did-btcr2/common';
|
|
2
|
+
import type { SignedBTCR2Update } from '@did-btcr2/cryptosuite';
|
|
3
|
+
import type { SchnorrKeyPair } from '@did-btcr2/keypair';
|
|
4
|
+
import type { SerializedSMTProof} from '@did-btcr2/smt';
|
|
5
|
+
import { blockHash, didToIndex, hashToHex, hexToHash, verifySerializedProof } from '@did-btcr2/smt';
|
|
6
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
7
|
+
import { Transaction } from 'bitcoinjs-lib';
|
|
8
|
+
import { AggregationCohort } from './cohort.js';
|
|
9
|
+
import { AggregationParticipantError } from './errors.js';
|
|
10
|
+
import type { BaseMessage } from './messages/base.js';
|
|
11
|
+
import {
|
|
12
|
+
AGGREGATED_NONCE,
|
|
13
|
+
AUTHORIZATION_REQUEST,
|
|
14
|
+
COHORT_ADVERT,
|
|
15
|
+
COHORT_OPT_IN_ACCEPT,
|
|
16
|
+
COHORT_READY,
|
|
17
|
+
DISTRIBUTE_AGGREGATED_DATA,
|
|
18
|
+
} from './messages/constants.js';
|
|
19
|
+
import {
|
|
20
|
+
createCohortOptInMessage,
|
|
21
|
+
createNonceContributionMessage,
|
|
22
|
+
createSignatureAuthorizationMessage,
|
|
23
|
+
createSubmitUpdateMessage,
|
|
24
|
+
createValidationAckMessage,
|
|
25
|
+
} from './messages/factories.js';
|
|
26
|
+
import type { ParticipantCohortPhaseType } from './phases.js';
|
|
27
|
+
import { ParticipantCohortPhase } from './phases.js';
|
|
28
|
+
import { BeaconSigningSession } from './signing-session.js';
|
|
29
|
+
|
|
30
|
+
/** Cohort advert as discovered by the participant (UI: list of joinable cohorts). */
|
|
31
|
+
export interface CohortAdvert {
|
|
32
|
+
cohortId: string;
|
|
33
|
+
serviceDid: string;
|
|
34
|
+
cohortSize: number;
|
|
35
|
+
network: string;
|
|
36
|
+
beaconType: string;
|
|
37
|
+
serviceCommunicationPk: Uint8Array;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Joined cohort info — available after the cohort is finalized. */
|
|
41
|
+
export interface JoinedCohortInfo {
|
|
42
|
+
cohortId: string;
|
|
43
|
+
serviceDid: string;
|
|
44
|
+
beaconAddress: string;
|
|
45
|
+
cohortKeys: Array<Uint8Array>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Aggregated data awaiting participant validation (UI: review for approval). */
|
|
49
|
+
export interface PendingValidation {
|
|
50
|
+
cohortId: string;
|
|
51
|
+
beaconType: string;
|
|
52
|
+
signalBytesHex: string;
|
|
53
|
+
casAnnouncement?: Record<string, string>;
|
|
54
|
+
smtProof?: SerializedSMTProof;
|
|
55
|
+
expectedHash: string;
|
|
56
|
+
matches: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Pending signing request (UI: review tx for approval). */
|
|
60
|
+
export interface PendingSigningRequest {
|
|
61
|
+
cohortId: string;
|
|
62
|
+
sessionId: string;
|
|
63
|
+
pendingTxHex: string;
|
|
64
|
+
prevOutValue: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Per-cohort participant state — internal. */
|
|
68
|
+
interface ParticipantCohortState {
|
|
69
|
+
phase: ParticipantCohortPhaseType;
|
|
70
|
+
cohortId: string;
|
|
71
|
+
serviceDid: string;
|
|
72
|
+
advert?: CohortAdvert;
|
|
73
|
+
cohort?: AggregationCohort;
|
|
74
|
+
submittedUpdate?: SignedBTCR2Update;
|
|
75
|
+
validation?: PendingValidation;
|
|
76
|
+
signingRequest?: PendingSigningRequest;
|
|
77
|
+
signingSession?: BeaconSigningSession;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface AggregationParticipantParams {
|
|
81
|
+
did: string;
|
|
82
|
+
keys: SchnorrKeyPair;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Sans-I/O state machine for an Aggregation Participant.
|
|
87
|
+
*
|
|
88
|
+
* Manages multiple cohorts simultaneously. The client app drives the state
|
|
89
|
+
* machine via `receive()` (for incoming messages) and explicit action methods
|
|
90
|
+
* (for user decisions). All outgoing messages are returned for the caller to
|
|
91
|
+
* send via whatever transport.
|
|
92
|
+
*
|
|
93
|
+
* @class AggregationParticipant
|
|
94
|
+
*/
|
|
95
|
+
export class AggregationParticipant {
|
|
96
|
+
public readonly did: string;
|
|
97
|
+
public readonly keys: SchnorrKeyPair;
|
|
98
|
+
|
|
99
|
+
/** Per-cohort state, keyed by cohortId. */
|
|
100
|
+
#cohortStates: Map<string, ParticipantCohortState> = new Map();
|
|
101
|
+
|
|
102
|
+
constructor({ did, keys }: AggregationParticipantParams) {
|
|
103
|
+
this.did = did;
|
|
104
|
+
this.keys = keys;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Process an incoming message. Updates internal state but never produces
|
|
110
|
+
* outgoing messages — those come exclusively from action methods.
|
|
111
|
+
*/
|
|
112
|
+
public receive(message: BaseMessage): void {
|
|
113
|
+
const type = message.type;
|
|
114
|
+
switch(type) {
|
|
115
|
+
case COHORT_ADVERT:
|
|
116
|
+
this.#handleCohortAdvert(message);
|
|
117
|
+
break;
|
|
118
|
+
case COHORT_OPT_IN_ACCEPT:
|
|
119
|
+
this.#handleOptInAccept(message);
|
|
120
|
+
break;
|
|
121
|
+
case COHORT_READY:
|
|
122
|
+
this.#handleCohortReady(message);
|
|
123
|
+
break;
|
|
124
|
+
case DISTRIBUTE_AGGREGATED_DATA:
|
|
125
|
+
this.#handleDistributeAggregatedData(message);
|
|
126
|
+
break;
|
|
127
|
+
case AUTHORIZATION_REQUEST:
|
|
128
|
+
this.#handleAuthorizationRequest(message);
|
|
129
|
+
break;
|
|
130
|
+
case AGGREGATED_NONCE:
|
|
131
|
+
this.#handleAggregatedNonce(message);
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
// Unknown message type — silently ignore
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/** Cohorts the participant has discovered but not yet joined. */
|
|
141
|
+
public get discoveredCohorts(): ReadonlyMap<string, CohortAdvert> {
|
|
142
|
+
const map = new Map<string, CohortAdvert>();
|
|
143
|
+
for(const [id, state] of this.#cohortStates) {
|
|
144
|
+
if(state.phase === ParticipantCohortPhase.Discovered && state.advert) {
|
|
145
|
+
map.set(id, state.advert);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return map;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#handleCohortAdvert(message: BaseMessage): void {
|
|
152
|
+
const cohortId = message.body?.cohortId;
|
|
153
|
+
if(!cohortId) return;
|
|
154
|
+
if(this.#cohortStates.has(cohortId)) return; // Already known
|
|
155
|
+
|
|
156
|
+
const advert: CohortAdvert = {
|
|
157
|
+
cohortId,
|
|
158
|
+
serviceDid : message.from,
|
|
159
|
+
cohortSize : message.body?.cohortSize ?? 0,
|
|
160
|
+
network : message.body?.network ?? '',
|
|
161
|
+
beaconType : message.body?.beaconType ?? 'CASBeacon',
|
|
162
|
+
serviceCommunicationPk : message.body?.communicationPk ?? new Uint8Array(),
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
this.#cohortStates.set(cohortId, {
|
|
166
|
+
phase : ParticipantCohortPhase.Discovered,
|
|
167
|
+
cohortId,
|
|
168
|
+
serviceDid : message.from,
|
|
169
|
+
advert,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* User action: join a discovered cohort.
|
|
175
|
+
* Returns the opt-in message to send.
|
|
176
|
+
*/
|
|
177
|
+
public joinCohort(cohortId: string): BaseMessage[] {
|
|
178
|
+
const state = this.#cohortStates.get(cohortId);
|
|
179
|
+
if(!state || state.phase !== ParticipantCohortPhase.Discovered) {
|
|
180
|
+
throw new AggregationParticipantError(
|
|
181
|
+
`Cannot join cohort ${cohortId}: not in Discovered phase.`,
|
|
182
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Create local cohort to track our view
|
|
187
|
+
const cohort = new AggregationCohort({
|
|
188
|
+
id : cohortId,
|
|
189
|
+
serviceDid : state.serviceDid,
|
|
190
|
+
minParticipants : state.advert!.cohortSize,
|
|
191
|
+
network : state.advert!.network,
|
|
192
|
+
beaconType : state.advert!.beaconType,
|
|
193
|
+
});
|
|
194
|
+
state.cohort = cohort;
|
|
195
|
+
state.phase = ParticipantCohortPhase.OptedIn;
|
|
196
|
+
|
|
197
|
+
const optInMessage = createCohortOptInMessage({
|
|
198
|
+
from : this.did,
|
|
199
|
+
to : state.serviceDid,
|
|
200
|
+
cohortId,
|
|
201
|
+
participantPk : this.keys.publicKey.compressed,
|
|
202
|
+
communicationPk : this.keys.publicKey.compressed,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return [optInMessage];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#handleOptInAccept(message: BaseMessage): void {
|
|
209
|
+
// Acknowledgment from service — no state change needed
|
|
210
|
+
void message;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
/** Cohorts that have been finalized — beacon address available. */
|
|
215
|
+
public get joinedCohorts(): ReadonlyMap<string, JoinedCohortInfo> {
|
|
216
|
+
const map = new Map<string, JoinedCohortInfo>();
|
|
217
|
+
for(const [id, state] of this.#cohortStates) {
|
|
218
|
+
if(state.cohort && state.cohort.beaconAddress) {
|
|
219
|
+
map.set(id, {
|
|
220
|
+
cohortId : id,
|
|
221
|
+
serviceDid : state.serviceDid,
|
|
222
|
+
beaconAddress : state.cohort.beaconAddress,
|
|
223
|
+
cohortKeys : state.cohort.cohortKeys,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return map;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#handleCohortReady(message: BaseMessage): void {
|
|
231
|
+
const cohortId = message.body?.cohortId;
|
|
232
|
+
if(!cohortId) return;
|
|
233
|
+
const state = this.#cohortStates.get(cohortId);
|
|
234
|
+
if(!state || !state.cohort) return;
|
|
235
|
+
if(state.phase !== ParticipantCohortPhase.OptedIn) return;
|
|
236
|
+
|
|
237
|
+
const beaconAddress = message.body?.beaconAddress;
|
|
238
|
+
const cohortKeys = message.body?.cohortKeys;
|
|
239
|
+
if(!beaconAddress || !cohortKeys) return;
|
|
240
|
+
|
|
241
|
+
const participantPkHex = bytesToHex(this.keys.publicKey.compressed);
|
|
242
|
+
const cohortKeysHex = cohortKeys.map(k => bytesToHex(new Uint8Array(k)));
|
|
243
|
+
|
|
244
|
+
state.cohort.validateMembership(participantPkHex, cohortKeysHex, beaconAddress);
|
|
245
|
+
state.phase = ParticipantCohortPhase.CohortReady;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* User action: submit a signed BTCR2 update for inclusion in the cohort's
|
|
251
|
+
* aggregated signal.
|
|
252
|
+
*/
|
|
253
|
+
public submitUpdate(cohortId: string, signedUpdate: SignedBTCR2Update): BaseMessage[] {
|
|
254
|
+
const state = this.#cohortStates.get(cohortId);
|
|
255
|
+
if(!state || state.phase !== ParticipantCohortPhase.CohortReady) {
|
|
256
|
+
throw new AggregationParticipantError(
|
|
257
|
+
`Cannot submit update to cohort ${cohortId}: not in CohortReady phase.`,
|
|
258
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
state.submittedUpdate = signedUpdate;
|
|
263
|
+
state.phase = ParticipantCohortPhase.UpdateSubmitted;
|
|
264
|
+
|
|
265
|
+
const message = createSubmitUpdateMessage({
|
|
266
|
+
from : this.did,
|
|
267
|
+
to : state.serviceDid,
|
|
268
|
+
cohortId,
|
|
269
|
+
signedUpdate : signedUpdate as unknown as Record<string, unknown>,
|
|
270
|
+
});
|
|
271
|
+
return [message];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
/** Aggregated data awaiting user validation. */
|
|
276
|
+
public get pendingValidations(): ReadonlyMap<string, PendingValidation> {
|
|
277
|
+
const map = new Map<string, PendingValidation>();
|
|
278
|
+
for(const [id, state] of this.#cohortStates) {
|
|
279
|
+
if(state.phase === ParticipantCohortPhase.AwaitingValidation && state.validation) {
|
|
280
|
+
map.set(id, state.validation);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return map;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
#handleDistributeAggregatedData(message: BaseMessage): void {
|
|
287
|
+
const cohortId = message.body?.cohortId;
|
|
288
|
+
if(!cohortId) return;
|
|
289
|
+
const state = this.#cohortStates.get(cohortId);
|
|
290
|
+
if(!state || state.phase !== ParticipantCohortPhase.UpdateSubmitted) return;
|
|
291
|
+
if(!state.submittedUpdate) return;
|
|
292
|
+
|
|
293
|
+
const beaconType = message.body?.beaconType;
|
|
294
|
+
const signalBytesHex = message.body?.signalBytesHex ?? '';
|
|
295
|
+
const expectedHash = canonicalHash(state.submittedUpdate);
|
|
296
|
+
let matches = false;
|
|
297
|
+
|
|
298
|
+
if(beaconType === 'CASBeacon') {
|
|
299
|
+
const casAnnouncement = message.body?.casAnnouncement;
|
|
300
|
+
if(casAnnouncement) {
|
|
301
|
+
matches = casAnnouncement[this.did] === expectedHash;
|
|
302
|
+
state.validation = {
|
|
303
|
+
cohortId,
|
|
304
|
+
beaconType,
|
|
305
|
+
signalBytesHex,
|
|
306
|
+
casAnnouncement,
|
|
307
|
+
expectedHash,
|
|
308
|
+
matches,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
} else if(beaconType === 'SMTBeacon') {
|
|
312
|
+
const smtProof = message.body?.smtProof as unknown as SerializedSMTProof | undefined;
|
|
313
|
+
if(smtProof?.updateId && smtProof?.nonce) {
|
|
314
|
+
// Verify updateId matches the canonicalized update hash
|
|
315
|
+
const canonicalBytes = new TextEncoder().encode(canonicalize(state.submittedUpdate));
|
|
316
|
+
const expectedUpdateId = hashToHex(blockHash(canonicalBytes));
|
|
317
|
+
if(smtProof.updateId === expectedUpdateId) {
|
|
318
|
+
// Verify Merkle inclusion
|
|
319
|
+
const index = didToIndex(this.did);
|
|
320
|
+
const candidateHash = blockHash(blockHash(hexToHash(smtProof.nonce)), hexToHash(smtProof.updateId));
|
|
321
|
+
matches = verifySerializedProof(smtProof, index, candidateHash);
|
|
322
|
+
}
|
|
323
|
+
state.validation = {
|
|
324
|
+
cohortId,
|
|
325
|
+
beaconType,
|
|
326
|
+
signalBytesHex,
|
|
327
|
+
smtProof,
|
|
328
|
+
expectedHash,
|
|
329
|
+
matches,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
state.phase = ParticipantCohortPhase.AwaitingValidation;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* User action: approve aggregated data and send validation ack.
|
|
339
|
+
*/
|
|
340
|
+
public approveValidation(cohortId: string): BaseMessage[] {
|
|
341
|
+
const state = this.#cohortStates.get(cohortId);
|
|
342
|
+
if(!state || state.phase !== ParticipantCohortPhase.AwaitingValidation) {
|
|
343
|
+
throw new AggregationParticipantError(
|
|
344
|
+
`Cannot approve validation for cohort ${cohortId}: not in AwaitingValidation phase.`,
|
|
345
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
state.phase = ParticipantCohortPhase.ValidationSent;
|
|
349
|
+
return [createValidationAckMessage({
|
|
350
|
+
from : this.did,
|
|
351
|
+
to : state.serviceDid,
|
|
352
|
+
cohortId,
|
|
353
|
+
approved : true,
|
|
354
|
+
})];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* User action: reject aggregated data and send rejection ack.
|
|
359
|
+
*/
|
|
360
|
+
public rejectValidation(cohortId: string): BaseMessage[] {
|
|
361
|
+
const state = this.#cohortStates.get(cohortId);
|
|
362
|
+
if(!state || state.phase !== ParticipantCohortPhase.AwaitingValidation) {
|
|
363
|
+
throw new AggregationParticipantError(
|
|
364
|
+
`Cannot reject validation for cohort ${cohortId}: not in AwaitingValidation phase.`,
|
|
365
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
state.phase = ParticipantCohortPhase.Failed;
|
|
369
|
+
return [createValidationAckMessage({
|
|
370
|
+
from : this.did,
|
|
371
|
+
to : state.serviceDid,
|
|
372
|
+
cohortId,
|
|
373
|
+
approved : false,
|
|
374
|
+
})];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
/** Signing requests awaiting user approval. */
|
|
379
|
+
public get pendingSigningRequests(): ReadonlyMap<string, PendingSigningRequest> {
|
|
380
|
+
const map = new Map<string, PendingSigningRequest>();
|
|
381
|
+
for(const [id, state] of this.#cohortStates) {
|
|
382
|
+
if(state.phase === ParticipantCohortPhase.AwaitingSigning && state.signingRequest) {
|
|
383
|
+
map.set(id, state.signingRequest);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return map;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
#handleAuthorizationRequest(message: BaseMessage): void {
|
|
390
|
+
const cohortId = message.body?.cohortId;
|
|
391
|
+
if(!cohortId) return;
|
|
392
|
+
const state = this.#cohortStates.get(cohortId);
|
|
393
|
+
if(!state || !state.cohort) return;
|
|
394
|
+
if(state.phase !== ParticipantCohortPhase.ValidationSent) return;
|
|
395
|
+
|
|
396
|
+
const sessionId = message.body?.sessionId;
|
|
397
|
+
const pendingTxHex = message.body?.pendingTx;
|
|
398
|
+
const prevOutValue = message.body?.prevOutValue;
|
|
399
|
+
if(!sessionId || !pendingTxHex || !prevOutValue) return;
|
|
400
|
+
|
|
401
|
+
state.signingRequest = {
|
|
402
|
+
cohortId,
|
|
403
|
+
sessionId,
|
|
404
|
+
pendingTxHex,
|
|
405
|
+
prevOutValue,
|
|
406
|
+
};
|
|
407
|
+
state.phase = ParticipantCohortPhase.AwaitingSigning;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* User action: approve signing and generate nonce contribution.
|
|
412
|
+
*/
|
|
413
|
+
public approveNonce(cohortId: string): BaseMessage[] {
|
|
414
|
+
const state = this.#cohortStates.get(cohortId);
|
|
415
|
+
if(!state || state.phase !== ParticipantCohortPhase.AwaitingSigning) {
|
|
416
|
+
throw new AggregationParticipantError(
|
|
417
|
+
`Cannot approve nonce for cohort ${cohortId}: not in AwaitingSigning phase.`,
|
|
418
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
if(!state.signingRequest || !state.cohort) {
|
|
422
|
+
throw new AggregationParticipantError(
|
|
423
|
+
`Cohort ${cohortId} missing signing request or cohort state.`,
|
|
424
|
+
'MISSING_STATE', { cohortId }
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const tx = Transaction.fromHex(state.signingRequest.pendingTxHex);
|
|
429
|
+
|
|
430
|
+
// Derive UTXO metadata for Taproot sighash (BIP-341).
|
|
431
|
+
// The beacon TX's change output (index 0) uses the same Taproot address as the input.
|
|
432
|
+
const prevOutScripts = tx.outs.length > 0 ? [tx.outs[0].script] : [];
|
|
433
|
+
const prevOutValues = [BigInt(state.signingRequest.prevOutValue)];
|
|
434
|
+
|
|
435
|
+
const session = new BeaconSigningSession({
|
|
436
|
+
id : state.signingRequest.sessionId,
|
|
437
|
+
cohort : state.cohort,
|
|
438
|
+
pendingTx : tx,
|
|
439
|
+
prevOutScripts,
|
|
440
|
+
prevOutValues,
|
|
441
|
+
});
|
|
442
|
+
state.signingSession = session;
|
|
443
|
+
|
|
444
|
+
const nonceContribution = session.generateNonceContribution(
|
|
445
|
+
this.keys.publicKey.compressed,
|
|
446
|
+
this.keys.secretKey.bytes
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
state.phase = ParticipantCohortPhase.NonceSent;
|
|
450
|
+
|
|
451
|
+
return [createNonceContributionMessage({
|
|
452
|
+
from : this.did,
|
|
453
|
+
to : state.serviceDid,
|
|
454
|
+
cohortId,
|
|
455
|
+
sessionId : session.id,
|
|
456
|
+
nonceContribution,
|
|
457
|
+
})];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
#handleAggregatedNonce(message: BaseMessage): void {
|
|
461
|
+
const cohortId = message.body?.cohortId;
|
|
462
|
+
if(!cohortId) return;
|
|
463
|
+
const state = this.#cohortStates.get(cohortId);
|
|
464
|
+
if(!state || !state.signingSession) return;
|
|
465
|
+
if(state.phase !== ParticipantCohortPhase.NonceSent) return;
|
|
466
|
+
|
|
467
|
+
const aggregatedNonce = message.body?.aggregatedNonce;
|
|
468
|
+
if(!aggregatedNonce) return;
|
|
469
|
+
|
|
470
|
+
state.signingSession.aggregatedNonce = aggregatedNonce;
|
|
471
|
+
state.phase = ParticipantCohortPhase.AwaitingPartialSig;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* User action: generate and return the partial signature.
|
|
476
|
+
* In most UIs this is automatic after AwaitingPartialSig — but exposing it
|
|
477
|
+
* as an explicit action lets the client UI confirm before signing if desired.
|
|
478
|
+
*/
|
|
479
|
+
public generatePartialSignature(cohortId: string): BaseMessage[] {
|
|
480
|
+
const state = this.#cohortStates.get(cohortId);
|
|
481
|
+
if(!state || state.phase !== ParticipantCohortPhase.AwaitingPartialSig) {
|
|
482
|
+
throw new AggregationParticipantError(
|
|
483
|
+
`Cannot generate partial signature for cohort ${cohortId}: not in AwaitingPartialSig phase.`,
|
|
484
|
+
'INVALID_PHASE', { cohortId, phase: state?.phase }
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
if(!state.signingSession) {
|
|
488
|
+
throw new AggregationParticipantError(
|
|
489
|
+
`No signing session for cohort ${cohortId}.`,
|
|
490
|
+
'MISSING_STATE', { cohortId }
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const partialSig = state.signingSession.generatePartialSignature(this.keys.secretKey.bytes);
|
|
495
|
+
state.phase = ParticipantCohortPhase.Complete;
|
|
496
|
+
|
|
497
|
+
return [createSignatureAuthorizationMessage({
|
|
498
|
+
from : this.did,
|
|
499
|
+
to : state.serviceDid,
|
|
500
|
+
cohortId,
|
|
501
|
+
sessionId : state.signingSession.id,
|
|
502
|
+
partialSignature : partialSig,
|
|
503
|
+
})];
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
public getCohortPhase(cohortId: string): ParticipantCohortPhaseType | undefined {
|
|
508
|
+
return this.#cohortStates.get(cohortId)?.phase;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phases for the did:btcr2 Aggregate Beacon protocol.
|
|
3
|
+
*
|
|
4
|
+
* The protocol has two roles (AggregationService and AggregationParticipant)
|
|
5
|
+
* which experience different phases for the same cohort. Each role has its own
|
|
6
|
+
* phase enum.
|
|
7
|
+
*
|
|
8
|
+
* The signing session has its own phase enum because MuSig2 signing is a
|
|
9
|
+
* sub-protocol within the larger aggregation protocol.
|
|
10
|
+
*/
|
|
11
|
+
export type ServiceCohortPhaseType =
|
|
12
|
+
| 'Created'
|
|
13
|
+
| 'Advertised'
|
|
14
|
+
| 'CohortSet'
|
|
15
|
+
| 'CollectingUpdates'
|
|
16
|
+
| 'UpdatesCollected'
|
|
17
|
+
| 'DataDistributed'
|
|
18
|
+
| 'Validated'
|
|
19
|
+
| 'SigningStarted'
|
|
20
|
+
| 'NoncesCollected'
|
|
21
|
+
| 'AwaitingPartialSigs'
|
|
22
|
+
| 'Complete'
|
|
23
|
+
| 'Failed';
|
|
24
|
+
|
|
25
|
+
export enum ServiceCohortPhase {
|
|
26
|
+
Created = 'Created',
|
|
27
|
+
Advertised = 'Advertised',
|
|
28
|
+
CohortSet = 'CohortSet',
|
|
29
|
+
CollectingUpdates = 'CollectingUpdates',
|
|
30
|
+
UpdatesCollected = 'UpdatesCollected',
|
|
31
|
+
DataDistributed = 'DataDistributed',
|
|
32
|
+
Validated = 'Validated',
|
|
33
|
+
SigningStarted = 'SigningStarted',
|
|
34
|
+
NoncesCollected = 'NoncesCollected',
|
|
35
|
+
AwaitingPartialSigs = 'AwaitingPartialSigs',
|
|
36
|
+
Complete = 'Complete',
|
|
37
|
+
Failed = 'Failed',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ParticipantCohortPhaseType =
|
|
41
|
+
| 'Discovered'
|
|
42
|
+
| 'OptedIn'
|
|
43
|
+
| 'CohortReady'
|
|
44
|
+
| 'UpdateSubmitted'
|
|
45
|
+
| 'AwaitingValidation'
|
|
46
|
+
| 'ValidationSent'
|
|
47
|
+
| 'AwaitingSigning'
|
|
48
|
+
| 'NonceSent'
|
|
49
|
+
| 'AwaitingPartialSig'
|
|
50
|
+
| 'Complete'
|
|
51
|
+
| 'Failed';
|
|
52
|
+
|
|
53
|
+
export enum ParticipantCohortPhase {
|
|
54
|
+
Discovered = 'Discovered',
|
|
55
|
+
OptedIn = 'OptedIn',
|
|
56
|
+
CohortReady = 'CohortReady',
|
|
57
|
+
UpdateSubmitted = 'UpdateSubmitted',
|
|
58
|
+
AwaitingValidation = 'AwaitingValidation',
|
|
59
|
+
ValidationSent = 'ValidationSent',
|
|
60
|
+
AwaitingSigning = 'AwaitingSigning',
|
|
61
|
+
NonceSent = 'NonceSent',
|
|
62
|
+
AwaitingPartialSig = 'AwaitingPartialSig',
|
|
63
|
+
Complete = 'Complete',
|
|
64
|
+
Failed = 'Failed',
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type SigningSessionPhaseType =
|
|
68
|
+
| 'AwaitingNonceContributions'
|
|
69
|
+
| 'NonceContributionsReceived'
|
|
70
|
+
| 'AwaitingPartialSignatures'
|
|
71
|
+
| 'PartialSignaturesReceived'
|
|
72
|
+
| 'Complete'
|
|
73
|
+
| 'Failed';
|
|
74
|
+
|
|
75
|
+
export enum SigningSessionPhase {
|
|
76
|
+
AwaitingNonceContributions = 'AwaitingNonceContributions',
|
|
77
|
+
NonceContributionsReceived = 'NonceContributionsReceived',
|
|
78
|
+
AwaitingPartialSignatures = 'AwaitingPartialSignatures',
|
|
79
|
+
PartialSignaturesReceived = 'PartialSignaturesReceived',
|
|
80
|
+
Complete = 'Complete',
|
|
81
|
+
Failed = 'Failed',
|
|
82
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CohortAdvert, PendingSigningRequest, PendingValidation } from '../participant.js';
|
|
2
|
+
import type { AggregationResult, PendingOptIn } from '../service.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AggregationServiceRunner events are emitted by the AggregationServiceRunner to signal important
|
|
6
|
+
* milestones and actions during the aggregation process. They can be listened to by external code
|
|
7
|
+
* to react to these events, such as logging, updating a UI, or triggering additional actions.
|
|
8
|
+
*/
|
|
9
|
+
export type AggregationServiceEvents = {
|
|
10
|
+
/** A cohort has been created and the advert message broadcast. */
|
|
11
|
+
'cohort-advertised': [{ cohortId: string }];
|
|
12
|
+
|
|
13
|
+
/** A participant has opted in. Fires before the accept decision callback. */
|
|
14
|
+
'opt-in-received': [PendingOptIn];
|
|
15
|
+
|
|
16
|
+
/** A participant has been accepted into the cohort. */
|
|
17
|
+
'participant-accepted': [{ participantDid: string }];
|
|
18
|
+
|
|
19
|
+
/** Keygen has been finalized — beacon address is now available. */
|
|
20
|
+
'keygen-complete': [{ cohortId: string; beaconAddress: string }];
|
|
21
|
+
|
|
22
|
+
/** A participant has submitted a signed update. */
|
|
23
|
+
'update-received': [{ participantDid: string }];
|
|
24
|
+
|
|
25
|
+
/** Aggregated data has been distributed to all participants for validation. */
|
|
26
|
+
'data-distributed': [{ cohortId: string }];
|
|
27
|
+
|
|
28
|
+
/** A participant has acknowledged validation (approved or rejected). */
|
|
29
|
+
'validation-received': [{ participantDid: string; approved: boolean }];
|
|
30
|
+
|
|
31
|
+
/** Signing has started — auth requests sent to participants. */
|
|
32
|
+
'signing-started': [{ sessionId: string }];
|
|
33
|
+
|
|
34
|
+
/** A participant has contributed their MuSig2 nonce. */
|
|
35
|
+
'nonce-received': [{ participantDid: string }];
|
|
36
|
+
|
|
37
|
+
/** Signing complete — final aggregated signature is ready to broadcast. */
|
|
38
|
+
'signing-complete': [AggregationResult];
|
|
39
|
+
|
|
40
|
+
/** A non-fatal error occurred. Fatal errors reject the run() promise. */
|
|
41
|
+
'error': [Error];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* AggregationParticipantRunner events are emitted by the AggregationParticipantRunner to signal
|
|
46
|
+
* important milestones and actions during the participant's involvement in the aggregation process.
|
|
47
|
+
* They can be listened to by external code to react to these events, such as logging, updating a
|
|
48
|
+
* UI, or triggering additional actions.
|
|
49
|
+
*/
|
|
50
|
+
export type AggregationParticipantEvents = {
|
|
51
|
+
/** A new cohort advert was discovered. Fires before the shouldJoin filter. */
|
|
52
|
+
'cohort-discovered': [CohortAdvert];
|
|
53
|
+
|
|
54
|
+
/** Participant has opted in to a cohort. */
|
|
55
|
+
'cohort-joined': [{ cohortId: string }];
|
|
56
|
+
|
|
57
|
+
/** Cohort keygen is complete — beacon address is now available. */
|
|
58
|
+
'cohort-ready': [{ cohortId: string; beaconAddress: string }];
|
|
59
|
+
|
|
60
|
+
/** Participant has submitted their signed update. */
|
|
61
|
+
'update-submitted': [{ cohortId: string }];
|
|
62
|
+
|
|
63
|
+
/** Aggregated data has arrived for validation. Fires before the validate callback. */
|
|
64
|
+
'validation-requested': [PendingValidation];
|
|
65
|
+
|
|
66
|
+
/** Signing request has arrived. Fires before the sign approval callback. */
|
|
67
|
+
'signing-requested': [PendingSigningRequest];
|
|
68
|
+
|
|
69
|
+
/** Cohort signing is complete from this participant's perspective. */
|
|
70
|
+
'cohort-complete': [{ cohortId: string; beaconAddress: string }];
|
|
71
|
+
|
|
72
|
+
/** Cohort failed (rejected validation, signing error, etc.). */
|
|
73
|
+
'cohort-failed': [{ cohortId: string; reason: string }];
|
|
74
|
+
|
|
75
|
+
/** A non-fatal error occurred. */
|
|
76
|
+
'error': [Error];
|
|
77
|
+
};
|