@bcts/frost-hubert 1.0.0-alpha.23 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/frost.cjs +344 -72
- package/dist/bin/frost.cjs.map +1 -1
- package/dist/bin/frost.mjs +344 -71
- package/dist/bin/frost.mjs.map +1 -1
- package/dist/busy-B_h0bNAJ.cjs +38 -0
- package/dist/busy-B_h0bNAJ.cjs.map +1 -0
- package/dist/busy-BlU8_pS2.mjs +27 -0
- package/dist/busy-BlU8_pS2.mjs.map +1 -0
- package/dist/cmd/index.cjs +27 -22
- package/dist/cmd/index.d.cts +2 -2
- package/dist/cmd/index.d.mts +2 -2
- package/dist/cmd/index.mjs +6 -3
- package/dist/cmd-CCVhHzG7.cjs +129 -0
- package/dist/cmd-CCVhHzG7.cjs.map +1 -0
- package/dist/cmd-DNsHd19v.mjs +112 -0
- package/dist/cmd-DNsHd19v.mjs.map +1 -0
- package/dist/common-7-BOgaTt.cjs +113 -0
- package/dist/common-7-BOgaTt.cjs.map +1 -0
- package/dist/common-Cf1UvJaP.mjs +282 -0
- package/dist/common-Cf1UvJaP.mjs.map +1 -0
- package/dist/common-CnvAUC2b.cjs +372 -0
- package/dist/common-CnvAUC2b.cjs.map +1 -0
- package/dist/common-DNrD_-EI.mjs +96 -0
- package/dist/common-DNrD_-EI.mjs.map +1 -0
- package/dist/dkg/index.cjs +6 -103
- package/dist/dkg/index.cjs.map +1 -1
- package/dist/dkg/index.d.cts +2 -2
- package/dist/dkg/index.d.mts +2 -2
- package/dist/dkg/index.mjs +4 -101
- package/dist/dkg/index.mjs.map +1 -1
- package/dist/finalize-BpC0rz93.mjs +389 -0
- package/dist/finalize-BpC0rz93.mjs.map +1 -0
- package/dist/finalize-Cb0obTSo.cjs +402 -0
- package/dist/finalize-Cb0obTSo.cjs.map +1 -0
- package/dist/finalize-DHEnKobp.cjs +303 -0
- package/dist/finalize-DHEnKobp.cjs.map +1 -0
- package/dist/finalize-DQ0VGUHO.cjs +265 -0
- package/dist/finalize-DQ0VGUHO.cjs.map +1 -0
- package/dist/finalize-DtRxHZ7H.mjs +290 -0
- package/dist/finalize-DtRxHZ7H.mjs.map +1 -0
- package/dist/finalize-T83Ko8nG.mjs +252 -0
- package/dist/finalize-T83Ko8nG.mjs.map +1 -0
- package/dist/frost/index.cjs +1 -1
- package/dist/frost/index.cjs.map +1 -1
- package/dist/frost/index.d.cts.map +1 -1
- package/dist/frost/index.d.mts.map +1 -1
- package/dist/frost/index.mjs +1 -1
- package/dist/frost/index.mjs.map +1 -1
- package/dist/{index-BJlwbPYu.d.cts → index-BErX9AZF.d.cts} +101 -79
- package/dist/index-BErX9AZF.d.cts.map +1 -0
- package/dist/{index-BkqLimZT.d.mts → index-BaUVw4b1.d.mts} +25 -2
- package/dist/index-BaUVw4b1.d.mts.map +1 -0
- package/dist/{index-BMbPgH0W.d.cts → index-CD50Qtgw.d.cts} +46 -2
- package/dist/index-CD50Qtgw.d.cts.map +1 -0
- package/dist/{index-DoV5HFvV.d.mts → index-CD50Qtgw.d.mts} +46 -2
- package/dist/index-CD50Qtgw.d.mts.map +1 -0
- package/dist/{index-Dzm1v4_4.d.mts → index-Drklne-Y.d.mts} +101 -79
- package/dist/index-Drklne-Y.d.mts.map +1 -0
- package/dist/{index-DmxfT59Y.d.cts → index-gkmZzEuD.d.cts} +25 -2
- package/dist/index-gkmZzEuD.d.cts.map +1 -0
- package/dist/index.cjs +30 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +8 -4
- package/dist/index.mjs.map +1 -1
- package/dist/invite-1tzg0B0P.cjs +274 -0
- package/dist/invite-1tzg0B0P.cjs.map +1 -0
- package/dist/invite-BLwtexAu.cjs +109 -0
- package/dist/invite-BLwtexAu.cjs.map +1 -0
- package/dist/invite-Be2v2SVc.mjs +96 -0
- package/dist/invite-Be2v2SVc.mjs.map +1 -0
- package/dist/invite-D8mQSnFz.mjs +219 -0
- package/dist/invite-D8mQSnFz.mjs.map +1 -0
- package/dist/parallel-PZiwHZT8.mjs +235 -0
- package/dist/parallel-PZiwHZT8.mjs.map +1 -0
- package/dist/parallel-szwYx-bi.cjs +318 -0
- package/dist/parallel-szwYx-bi.cjs.map +1 -0
- package/dist/proposed-participant-BvHNnpcZ.cjs +140 -0
- package/dist/proposed-participant-BvHNnpcZ.cjs.map +1 -0
- package/dist/proposed-participant-Detb823_.mjs +129 -0
- package/dist/proposed-participant-Detb823_.mjs.map +1 -0
- package/dist/receive-BR-knnGv.cjs +213 -0
- package/dist/receive-BR-knnGv.cjs.map +1 -0
- package/dist/receive-D_r4Mryr.cjs +190 -0
- package/dist/receive-D_r4Mryr.cjs.map +1 -0
- package/dist/receive-dkSCSGpl.mjs +188 -0
- package/dist/receive-dkSCSGpl.mjs.map +1 -0
- package/dist/receive-g8EhZF2Y.mjs +177 -0
- package/dist/receive-g8EhZF2Y.mjs.map +1 -0
- package/dist/registry/index.cjs +86 -11
- package/dist/registry/index.cjs.map +1 -1
- package/dist/registry/index.d.cts +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +85 -10
- package/dist/registry/index.mjs.map +1 -1
- package/dist/{registry-loI1_Mh1.cjs → registry-CkIbA7nt.cjs} +79 -2
- package/dist/registry-CkIbA7nt.cjs.map +1 -0
- package/dist/{registry-CgrCZ4En.mjs → registry-DGjs4qDK.mjs} +74 -3
- package/dist/registry-DGjs4qDK.mjs.map +1 -0
- package/dist/round1-9FAqFvL5.cjs +465 -0
- package/dist/round1-9FAqFvL5.cjs.map +1 -0
- package/dist/round1-B8haiMM8.mjs +208 -0
- package/dist/round1-B8haiMM8.mjs.map +1 -0
- package/dist/round1-BOIE1E4O.mjs +452 -0
- package/dist/round1-BOIE1E4O.mjs.map +1 -0
- package/dist/round1-Bq0vweyQ.cjs +422 -0
- package/dist/round1-Bq0vweyQ.cjs.map +1 -0
- package/dist/round1-CXkXoVQU.cjs +208 -0
- package/dist/round1-CXkXoVQU.cjs.map +1 -0
- package/dist/round1-D8t7EzIo.mjs +373 -0
- package/dist/round1-D8t7EzIo.mjs.map +1 -0
- package/dist/round1-DriPu15x.cjs +221 -0
- package/dist/round1-DriPu15x.cjs.map +1 -0
- package/dist/round1-Y2kcVwnR.mjs +195 -0
- package/dist/round1-Y2kcVwnR.mjs.map +1 -0
- package/dist/round2-AMDYMUIg.cjs +305 -0
- package/dist/round2-AMDYMUIg.cjs.map +1 -0
- package/dist/round2-BHQKVJFo.cjs +410 -0
- package/dist/round2-BHQKVJFo.cjs.map +1 -0
- package/dist/round2-BfetYacV.mjs +450 -0
- package/dist/round2-BfetYacV.mjs.map +1 -0
- package/dist/round2-Cf5CJc_8.mjs +397 -0
- package/dist/round2-Cf5CJc_8.mjs.map +1 -0
- package/dist/round2-CvrmylN1.cjs +293 -0
- package/dist/round2-CvrmylN1.cjs.map +1 -0
- package/dist/round2-Dk_w97nl.cjs +499 -0
- package/dist/round2-Dk_w97nl.cjs.map +1 -0
- package/dist/round2-Z2JhMwxc.mjs +292 -0
- package/dist/round2-Z2JhMwxc.mjs.map +1 -0
- package/dist/round2-mF6UlkT-.mjs +280 -0
- package/dist/round2-mF6UlkT-.mjs.map +1 -0
- package/package.json +14 -14
- package/src/bin/frost.ts +849 -128
- package/src/cmd/common.ts +19 -1
- package/src/cmd/dkg/common.ts +97 -10
- package/src/cmd/dkg/coordinator/invite.ts +5 -2
- package/src/cmd/dkg/participant/finalize.ts +51 -17
- package/src/cmd/dkg/participant/round1.ts +39 -38
- package/src/cmd/dkg/participant/round2.ts +60 -26
- package/src/cmd/sign/coordinator/round2.ts +5 -1
- package/src/cmd/sign/participant/finalize.ts +6 -2
- package/src/cmd/sign/participant/receive.ts +5 -2
- package/src/dkg/group-invite.ts +12 -2
- package/src/dkg/proposed-participant.ts +32 -3
- package/src/registry/owner-record.ts +12 -0
- package/src/registry/participant-record.ts +35 -2
- package/src/registry/registry-impl.ts +74 -18
- package/dist/cmd-5yLeC_QL.mjs +0 -4708
- package/dist/cmd-5yLeC_QL.mjs.map +0 -1
- package/dist/cmd-BfZjC3Uh.cjs +0 -4847
- package/dist/cmd-BfZjC3Uh.cjs.map +0 -1
- package/dist/index-BJlwbPYu.d.cts.map +0 -1
- package/dist/index-BMbPgH0W.d.cts.map +0 -1
- package/dist/index-BkqLimZT.d.mts.map +0 -1
- package/dist/index-DmxfT59Y.d.cts.map +0 -1
- package/dist/index-DoV5HFvV.d.mts.map +0 -1
- package/dist/index-Dzm1v4_4.d.mts.map +0 -1
- package/dist/registry-CgrCZ4En.mjs.map +0 -1
- package/dist/registry-loI1_Mh1.cjs.map +0 -1
- /package/dist/{chunk-CZWwpsFl.cjs → chunk-DakpK96I.cjs} +0 -0
- /package/dist/{chunk-CjcI7cDX.mjs → chunk-z9aeyW2b.mjs} +0 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
const require_chunk = require("./chunk-DakpK96I.cjs");
|
|
2
|
+
const require_proposed_participant = require("./proposed-participant-BvHNnpcZ.cjs");
|
|
3
|
+
const require_registry_index = require("./registry/index.cjs");
|
|
4
|
+
const require_common = require("./common-CnvAUC2b.cjs");
|
|
5
|
+
const require_busy = require("./busy-B_h0bNAJ.cjs");
|
|
6
|
+
const require_frost_index = require("./frost/index.cjs");
|
|
7
|
+
const require_common$1 = require("./common-7-BOgaTt.cjs");
|
|
8
|
+
let _bcts_components = require("@bcts/components");
|
|
9
|
+
let _bcts_envelope = require("@bcts/envelope");
|
|
10
|
+
let _bcts_gstp = require("@bcts/gstp");
|
|
11
|
+
let node_fs = require("node:fs");
|
|
12
|
+
node_fs = require_chunk.__toESM(node_fs, 1);
|
|
13
|
+
let node_path = require("node:path");
|
|
14
|
+
node_path = require_chunk.__toESM(node_path, 1);
|
|
15
|
+
//#region src/cmd/sign/participant/finalize.ts
|
|
16
|
+
/**
|
|
17
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
18
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
19
|
+
*
|
|
20
|
+
*
|
|
21
|
+
* Sign participant finalize command.
|
|
22
|
+
*
|
|
23
|
+
* Port of cmd/sign/participant/finalize.rs from frost-hubert-rust.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
var finalize_exports = /* @__PURE__ */ require_chunk.__exportAll({ finalize: () => finalize });
|
|
28
|
+
/**
|
|
29
|
+
* Load the receive state for a signing session.
|
|
30
|
+
*
|
|
31
|
+
* Searches for sign_receive.json in group-state directories.
|
|
32
|
+
*
|
|
33
|
+
* Port of `load_receive_state()` from cmd/sign/participant/finalize.rs.
|
|
34
|
+
*/
|
|
35
|
+
function loadReceiveState(registryPath, sessionId, groupHint) {
|
|
36
|
+
const base = node_path.dirname(registryPath);
|
|
37
|
+
const groupStateDir = node_path.join(base, "group-state");
|
|
38
|
+
const groupDirs = [];
|
|
39
|
+
if (groupHint !== void 0) groupDirs.push([groupHint, node_path.join(groupStateDir, groupHint.hex())]);
|
|
40
|
+
else if (node_fs.existsSync(groupStateDir)) {
|
|
41
|
+
for (const entry of node_fs.readdirSync(groupStateDir, { withFileTypes: true })) if (entry.isDirectory()) {
|
|
42
|
+
const name = entry.name;
|
|
43
|
+
if (name.length === 64 && /^[0-9a-f]+$/i.test(name)) {
|
|
44
|
+
const groupId = _bcts_components.ARID.fromHex(name);
|
|
45
|
+
groupDirs.push([groupId, node_path.join(groupStateDir, name)]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const candidates = [];
|
|
50
|
+
for (const [groupId, groupDir] of groupDirs) {
|
|
51
|
+
const candidate = node_path.join(groupDir, "signing", sessionId.hex(), "sign_receive.json");
|
|
52
|
+
if (node_fs.existsSync(candidate)) candidates.push([groupId, candidate]);
|
|
53
|
+
}
|
|
54
|
+
if (candidates.length === 0) throw new Error("No sign_receive.json found for this session; run `frost sign participant receive` first");
|
|
55
|
+
if (candidates.length > 1) throw new Error("Multiple groups contain this session; use --group to disambiguate");
|
|
56
|
+
const [groupId, filePath] = candidates[0];
|
|
57
|
+
const raw = JSON.parse(node_fs.readFileSync(filePath, "utf-8"));
|
|
58
|
+
const getStr = (key) => {
|
|
59
|
+
const val = raw[key];
|
|
60
|
+
if (typeof val !== "string") throw new Error(`Missing or invalid ${key} in sign_receive.json`);
|
|
61
|
+
return val;
|
|
62
|
+
};
|
|
63
|
+
const sessionInState = require_common.parseAridUr(getStr("session"));
|
|
64
|
+
if (sessionInState.hex() !== sessionId.hex()) throw new Error(`Session ${sessionInState.urString()} in sign_receive.json does not match requested session ${sessionId.urString()}`);
|
|
65
|
+
const groupInState = require_common.parseAridUr(getStr("group"));
|
|
66
|
+
if (groupInState.hex() !== groupId.hex()) throw new Error(`Group ${groupInState.urString()} in sign_receive.json does not match directory group ${groupId.urString()}`);
|
|
67
|
+
const coordinator = _bcts_components.XID.fromURString(getStr("coordinator"));
|
|
68
|
+
const participantsVal = raw["participants"];
|
|
69
|
+
if (!Array.isArray(participantsVal)) throw new Error("Missing participants in sign_receive.json");
|
|
70
|
+
const participants = [];
|
|
71
|
+
for (const entry of participantsVal) {
|
|
72
|
+
if (typeof entry !== "string") throw new Error("Invalid participant entry in sign_receive.json");
|
|
73
|
+
participants.push(_bcts_components.XID.fromURString(entry));
|
|
74
|
+
}
|
|
75
|
+
const minSignersVal = raw["min_signers"];
|
|
76
|
+
if (typeof minSignersVal !== "number") throw new Error("Missing min_signers in sign_receive.json");
|
|
77
|
+
const minSigners = minSignersVal;
|
|
78
|
+
const targetUr = getStr("target");
|
|
79
|
+
participants.sort((a, b) => require_proposed_participant.compareXidBytes(a.toData(), b.toData()));
|
|
80
|
+
return {
|
|
81
|
+
groupId,
|
|
82
|
+
coordinator,
|
|
83
|
+
participants,
|
|
84
|
+
minSigners,
|
|
85
|
+
targetUr
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Load the share state for a signing session.
|
|
90
|
+
*
|
|
91
|
+
* Port of `load_share_state()` from cmd/sign/participant/finalize.rs.
|
|
92
|
+
*/
|
|
93
|
+
function loadShareState(registryPath, groupId, sessionId) {
|
|
94
|
+
const dir = require_common$1.signingStateDir(registryPath, groupId.hex(), sessionId.hex());
|
|
95
|
+
const filePath = node_path.join(dir, "share.json");
|
|
96
|
+
if (!node_fs.existsSync(filePath)) throw new Error(`Signature share state not found at ${filePath}. Run \`frost sign participant share\` first.`);
|
|
97
|
+
const raw = JSON.parse(node_fs.readFileSync(filePath, "utf-8"));
|
|
98
|
+
const getStr = (key) => {
|
|
99
|
+
const val = raw[key];
|
|
100
|
+
if (typeof val !== "string") throw new Error(`Missing or invalid ${key} in share.json`);
|
|
101
|
+
return val;
|
|
102
|
+
};
|
|
103
|
+
const sessionInState = require_common.parseAridUr(getStr("session"));
|
|
104
|
+
if (sessionInState.hex() !== sessionId.hex()) throw new Error(`Session ${sessionInState.urString()} in share.json does not match requested session ${sessionId.urString()}`);
|
|
105
|
+
const finalizeArid = require_common.parseAridUr(getStr("finalize_arid"));
|
|
106
|
+
const signatureShare = require_frost_index.deserializeSignatureShare(getStr("signature_share"));
|
|
107
|
+
const commitmentsVal = raw["commitments"];
|
|
108
|
+
if (typeof commitmentsVal !== "object" || commitmentsVal === null) throw new Error("Missing commitments map in share.json");
|
|
109
|
+
const commitments = /* @__PURE__ */ new Map();
|
|
110
|
+
for (const [xidStr, value] of Object.entries(commitmentsVal)) {
|
|
111
|
+
const commits = require_frost_index.deserializeSigningCommitments(value);
|
|
112
|
+
commitments.set(xidStr, commits);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
finalizeArid,
|
|
116
|
+
signatureShare,
|
|
117
|
+
commitments
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Validate that session state is consistent with registry and owner.
|
|
122
|
+
*
|
|
123
|
+
* Port of `validate_session_state()` from cmd/sign/participant/finalize.rs.
|
|
124
|
+
*/
|
|
125
|
+
function validateSessionState(receiveState, groupRecord, owner) {
|
|
126
|
+
if (receiveState.coordinator.urString() !== groupRecord.coordinator().xid().urString()) throw new Error("Coordinator in session state does not match registry");
|
|
127
|
+
const ownerXidStr = owner.xid().urString();
|
|
128
|
+
if (!receiveState.participants.some((p) => p.urString() === ownerXidStr)) throw new Error("This participant is not part of the signing session");
|
|
129
|
+
if (groupRecord.minSigners() !== receiveState.minSigners) throw new Error(`Session min_signers ${receiveState.minSigners} does not match registry ${groupRecord.minSigners()}`);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Validate share state against receive state and registry.
|
|
133
|
+
*
|
|
134
|
+
* Port of `validate_share_state()` from cmd/sign/participant/finalize.rs.
|
|
135
|
+
*/
|
|
136
|
+
function validateShareState(shareState, receiveState, groupRecord) {
|
|
137
|
+
const listeningAtArid = groupRecord.listeningAtArid();
|
|
138
|
+
if (listeningAtArid === void 0) throw new Error("No listening ARID for signFinalize. Did you run `frost sign participant share`?");
|
|
139
|
+
if (shareState.finalizeArid.hex() !== listeningAtArid.hex()) throw new Error(`Registry listening ARID (${listeningAtArid.urString()}) does not match persisted finalize ARID (${shareState.finalizeArid.urString()})`);
|
|
140
|
+
const commitParticipants = new Set(shareState.commitments.keys());
|
|
141
|
+
const sessionParticipants = new Set(receiveState.participants.map((p) => p.urString()));
|
|
142
|
+
if (commitParticipants.size !== sessionParticipants.size) throw new Error("Commitments do not match session participants");
|
|
143
|
+
for (const p of commitParticipants) if (!sessionParticipants.has(p)) throw new Error("Commitments do not match session participants");
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Validate the finalize event.
|
|
147
|
+
*
|
|
148
|
+
* Port of `validate_finalize_event()` from cmd/sign/participant/finalize.rs.
|
|
149
|
+
*/
|
|
150
|
+
function validateFinalizeEvent(sealedEvent, sessionId, groupRecord) {
|
|
151
|
+
const sessionEnvelope = sealedEvent.content().objectForPredicate("session");
|
|
152
|
+
if (sessionEnvelope === void 0) throw new Error("Missing session in finalize event");
|
|
153
|
+
const eventSession = _bcts_components.ARID.fromTaggedCbor(sessionEnvelope.subject().tryLeaf());
|
|
154
|
+
if (eventSession.hex() !== sessionId.hex()) throw new Error(`Event session ${eventSession.urString()} does not match expected ${sessionId.urString()}`);
|
|
155
|
+
const expectedCoordinator = groupRecord.coordinator().xid();
|
|
156
|
+
if (sealedEvent.sender().xid().urString() !== expectedCoordinator.urString()) throw new Error(`Unexpected event sender: ${sealedEvent.sender().xid().urString()} (expected coordinator ${expectedCoordinator.urString()})`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Validate signature shares from the finalize event.
|
|
160
|
+
*
|
|
161
|
+
* Port of `validate_signature_shares()` from cmd/sign/participant/finalize.rs.
|
|
162
|
+
*/
|
|
163
|
+
function validateSignatureShares(signatureSharesByXid, receiveState, _shareState, owner) {
|
|
164
|
+
if (signatureSharesByXid.size < receiveState.minSigners) throw new Error(`Finalize package contains ${signatureSharesByXid.size} signature shares but requires at least ${receiveState.minSigners}`);
|
|
165
|
+
const sharesParticipants = new Set(signatureSharesByXid.keys());
|
|
166
|
+
const sessionParticipants = new Set(receiveState.participants.map((p) => p.urString()));
|
|
167
|
+
if (sharesParticipants.size !== sessionParticipants.size) throw new Error("Signature share set does not match session participants");
|
|
168
|
+
for (const p of sharesParticipants) if (!sessionParticipants.has(p)) throw new Error("Signature share set does not match session participants");
|
|
169
|
+
const ownerXidStr = owner.xid().urString();
|
|
170
|
+
if (signatureSharesByXid.get(ownerXidStr) === void 0) throw new Error("Finalize package is missing this participant's signature share");
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Fetch and parse the finalize event from storage.
|
|
174
|
+
*
|
|
175
|
+
* Port of `fetch_finalize_event()` from cmd/sign/participant/finalize.rs.
|
|
176
|
+
*/
|
|
177
|
+
async function fetchFinalizeEvent(client, finalizeArid, timeout, owner) {
|
|
178
|
+
if (require_common.isVerbose()) console.error("Fetching finalize package from Hubert...");
|
|
179
|
+
const finalizeEnvelope = await require_busy.getWithIndicator(client, finalizeArid, "Finalize package", timeout, require_common.isVerbose());
|
|
180
|
+
if (finalizeEnvelope === null || finalizeEnvelope === void 0) throw new Error("Finalize package not found in Hubert storage");
|
|
181
|
+
const signerKeys = owner.xidDocument().inceptionPrivateKeys();
|
|
182
|
+
if (signerKeys === void 0) throw new Error("Owner XID document has no inception private keys");
|
|
183
|
+
return _bcts_gstp.SealedEvent.tryFromEnvelope(finalizeEnvelope, void 0, void 0, signerKeys, (env) => {
|
|
184
|
+
require_common$1.SignFinalizeContent.fromEnvelope(env);
|
|
185
|
+
return env;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Parse signature shares from the finalize event.
|
|
190
|
+
*
|
|
191
|
+
* Port of `parse_signature_shares()` from cmd/sign/participant/finalize.rs.
|
|
192
|
+
*/
|
|
193
|
+
function parseSignatureShares(event) {
|
|
194
|
+
const contentEnvelope = event.content();
|
|
195
|
+
const shares = /* @__PURE__ */ new Map();
|
|
196
|
+
const entries = contentEnvelope.objectsForPredicate("signature_share");
|
|
197
|
+
for (const entry of entries) {
|
|
198
|
+
const xid = _bcts_components.XID.fromTaggedCbor(entry.subject().tryLeaf());
|
|
199
|
+
const shareEnvelope = entry.objectForPredicate("share");
|
|
200
|
+
if (shareEnvelope === void 0) throw new Error("Missing share in signature_share entry");
|
|
201
|
+
const share = require_frost_index.deserializeSignatureShare(shareEnvelope.extractString());
|
|
202
|
+
const xidStr = xid.urString();
|
|
203
|
+
if (shares.has(xidStr)) throw new Error(`Duplicate signature share for participant ${xidStr}`);
|
|
204
|
+
shares.set(xidStr, share);
|
|
205
|
+
}
|
|
206
|
+
if (shares.size === 0) throw new Error("Finalize package contains no signature shares");
|
|
207
|
+
return shares;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Build a mapping from XID to FROST identifier.
|
|
211
|
+
*
|
|
212
|
+
* Port of `xid_identifier_map()` from cmd/sign/participant/finalize.rs.
|
|
213
|
+
*/
|
|
214
|
+
function xidIdentifierMap(participants) {
|
|
215
|
+
const map = /* @__PURE__ */ new Map();
|
|
216
|
+
for (let i = 0; i < participants.length; i++) {
|
|
217
|
+
const xid = participants[i];
|
|
218
|
+
const identifier = require_frost_index.identifierFromU16(i + 1);
|
|
219
|
+
map.set(xid.urString(), identifier);
|
|
220
|
+
}
|
|
221
|
+
return map;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Convert commitments from XID-keyed to Identifier-keyed map.
|
|
225
|
+
*
|
|
226
|
+
* Port of `commitments_with_identifiers()` from cmd/sign/participant/finalize.rs.
|
|
227
|
+
*/
|
|
228
|
+
function commitmentsWithIdentifiers(commitments, xidToIdentifier) {
|
|
229
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
230
|
+
for (const [xidStr, commits] of commitments) {
|
|
231
|
+
const identifier = xidToIdentifier.get(xidStr);
|
|
232
|
+
if (identifier === void 0) throw new Error(`Unknown participant ${xidStr}`);
|
|
233
|
+
mapped.set(identifier, commits);
|
|
234
|
+
}
|
|
235
|
+
return mapped;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Convert signature shares from XID-keyed to Identifier-keyed map.
|
|
239
|
+
*
|
|
240
|
+
* Port of `signature_shares_with_identifiers()` from cmd/sign/participant/finalize.rs.
|
|
241
|
+
*/
|
|
242
|
+
function signatureSharesWithIdentifiers(shares, xidToIdentifier) {
|
|
243
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const [xidStr, share] of shares) {
|
|
245
|
+
const identifier = xidToIdentifier.get(xidStr);
|
|
246
|
+
if (identifier === void 0) throw new Error(`Unknown participant ${xidStr}`);
|
|
247
|
+
mapped.set(identifier, share);
|
|
248
|
+
}
|
|
249
|
+
return mapped;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Load the public key package for a group.
|
|
253
|
+
*
|
|
254
|
+
* Port of `load_public_key_package()` from cmd/sign/participant/finalize.rs.
|
|
255
|
+
*/
|
|
256
|
+
function loadPublicKeyPackage(registryPath, groupId) {
|
|
257
|
+
const base = node_path.dirname(registryPath);
|
|
258
|
+
const directPath = node_path.join(base, "group-state", groupId.hex(), "public_key_package.json");
|
|
259
|
+
if (node_fs.existsSync(directPath)) {
|
|
260
|
+
const raw = JSON.parse(node_fs.readFileSync(directPath, "utf-8"));
|
|
261
|
+
return {
|
|
262
|
+
package: require_frost_index.deserializePublicKeyPackage(raw),
|
|
263
|
+
verifyingKeyHex: raw.verifyingKey
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const collectedPath = node_path.join(base, "group-state", groupId.hex(), "collected_finalize.json");
|
|
267
|
+
if (node_fs.existsSync(collectedPath)) {
|
|
268
|
+
const raw = JSON.parse(node_fs.readFileSync(collectedPath, "utf-8"));
|
|
269
|
+
const firstEntry = Object.values(raw)[0];
|
|
270
|
+
if (firstEntry === void 0) throw new Error("collected_finalize.json is empty");
|
|
271
|
+
const publicKeyValue = firstEntry["public_key_package"];
|
|
272
|
+
if (publicKeyValue === void 0) throw new Error("public_key_package missing in collected_finalize.json");
|
|
273
|
+
return {
|
|
274
|
+
package: require_frost_index.deserializePublicKeyPackage(publicKeyValue),
|
|
275
|
+
verifyingKeyHex: publicKeyValue.verifyingKey
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
throw new Error(`Public key package not found for group ${groupId.urString()}; run finalize respond/collect first`);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Aggregate signature shares and verify the result.
|
|
282
|
+
*
|
|
283
|
+
* Port of `aggregate_and_verify_signature()` from cmd/sign/participant/finalize.rs.
|
|
284
|
+
*/
|
|
285
|
+
function aggregateAndVerifySignature(registryPath, groupId, participants, commitments, signatureSharesByXid, targetEnvelope, targetDigest) {
|
|
286
|
+
const xidToIdentifier = xidIdentifierMap(participants);
|
|
287
|
+
const signingPackage = require_frost_index.createSigningPackage(commitmentsWithIdentifiers(commitments, xidToIdentifier), targetDigest.data());
|
|
288
|
+
const signatureSharesByIdentifier = signatureSharesWithIdentifiers(signatureSharesByXid, xidToIdentifier);
|
|
289
|
+
const { package: publicKeyPackage, verifyingKeyHex } = loadPublicKeyPackage(registryPath, groupId);
|
|
290
|
+
const verifyingKey = require_common.signingKeyFromVerifying(require_frost_index.hexToBytes(verifyingKeyHex));
|
|
291
|
+
const sigBytes = require_frost_index.serializeSignature(require_frost_index.aggregateSignatures(signingPackage, signatureSharesByIdentifier, publicKeyPackage));
|
|
292
|
+
if (sigBytes.length !== 64) throw new Error("Aggregated signature is not 64 bytes");
|
|
293
|
+
const finalSignature = _bcts_components.Signature.ed25519FromData(sigBytes);
|
|
294
|
+
if (!verifyingKey.verify(finalSignature, targetDigest.data())) throw new Error("Aggregated signature failed verification against target digest");
|
|
295
|
+
const signedEnvelope = targetEnvelope.addAssertion("signed", finalSignature);
|
|
296
|
+
signedEnvelope.verifySignatureFrom(verifyingKey);
|
|
297
|
+
return [
|
|
298
|
+
finalSignature,
|
|
299
|
+
signedEnvelope,
|
|
300
|
+
verifyingKey
|
|
301
|
+
];
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Update the registry verifying key if needed.
|
|
305
|
+
*
|
|
306
|
+
* Port of `update_registry_verifying_key()` from cmd/sign/participant/finalize.rs.
|
|
307
|
+
*/
|
|
308
|
+
function updateRegistryVerifyingKey(registry, registryPath, groupId, verifyingKey, groupRecord) {
|
|
309
|
+
const existing = groupRecord.verifyingKey();
|
|
310
|
+
if (existing !== void 0) {
|
|
311
|
+
if (existing.urString() !== verifyingKey.urString()) throw new Error("Registry verifying key does not match finalize package");
|
|
312
|
+
} else {
|
|
313
|
+
const mutableGroup = registry.group(groupId);
|
|
314
|
+
if (mutableGroup === void 0) throw new Error("Group not found in registry");
|
|
315
|
+
mutableGroup.setVerifyingKey(verifyingKey);
|
|
316
|
+
registry.save(registryPath);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Persist the final state to disk.
|
|
321
|
+
*
|
|
322
|
+
* Port of `persist_final_state()` from cmd/sign/participant/finalize.rs.
|
|
323
|
+
*/
|
|
324
|
+
function persistFinalState(registryPath, groupId, sessionId, signature, signedEnvelope, signatureShares, shareState) {
|
|
325
|
+
const dir = require_common$1.signingStateDir(registryPath, groupId.hex(), sessionId.hex());
|
|
326
|
+
node_fs.mkdirSync(dir, { recursive: true });
|
|
327
|
+
const finalPath = node_path.join(dir, "final.json");
|
|
328
|
+
let root = {};
|
|
329
|
+
if (node_fs.existsSync(finalPath)) root = JSON.parse(node_fs.readFileSync(finalPath, "utf-8"));
|
|
330
|
+
const sharesJson = {};
|
|
331
|
+
for (const [xidStr, share] of signatureShares) sharesJson[xidStr] = require_frost_index.serializeSignatureShare(share);
|
|
332
|
+
const commitmentsJson = {};
|
|
333
|
+
for (const [xidStr, commits] of shareState.commitments) commitmentsJson[xidStr] = require_frost_index.serializeSigningCommitments(commits);
|
|
334
|
+
root["group"] = groupId.urString();
|
|
335
|
+
root["session"] = sessionId.urString();
|
|
336
|
+
root["signature"] = signature.urString();
|
|
337
|
+
root["signature_shares"] = sharesJson;
|
|
338
|
+
root["commitments"] = commitmentsJson;
|
|
339
|
+
root["finalize_arid"] = shareState.finalizeArid.urString();
|
|
340
|
+
root["signed_target"] = signedEnvelope.urString();
|
|
341
|
+
node_fs.writeFileSync(finalPath, JSON.stringify(root, null, 2));
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Execute the sign participant finalize command.
|
|
345
|
+
*
|
|
346
|
+
* Receives the finalize event with aggregated signature.
|
|
347
|
+
*
|
|
348
|
+
* Port of `finalize()` from cmd/sign/participant/finalize.rs.
|
|
349
|
+
*/
|
|
350
|
+
async function finalize(client, options, cwd) {
|
|
351
|
+
const registryPath = require_registry_index.resolveRegistryPath(options.registryPath, cwd);
|
|
352
|
+
const registry = require_registry_index.Registry.load(registryPath);
|
|
353
|
+
const owner = registry.owner();
|
|
354
|
+
if (owner === void 0) throw new Error("Registry owner is required");
|
|
355
|
+
const sessionId = require_common.parseAridUr(options.sessionId);
|
|
356
|
+
const receiveState = loadReceiveState(registryPath, sessionId, options.groupId !== void 0 && options.groupId !== "" ? require_common.parseAridUr(options.groupId) : void 0);
|
|
357
|
+
const groupId = receiveState.groupId;
|
|
358
|
+
const groupRecord = registry.group(groupId);
|
|
359
|
+
if (groupRecord === void 0) throw new Error("Group not found in registry");
|
|
360
|
+
validateSessionState(receiveState, groupRecord, owner);
|
|
361
|
+
const shareState = loadShareState(registryPath, groupId, sessionId);
|
|
362
|
+
validateShareState(shareState, receiveState, groupRecord);
|
|
363
|
+
const sealedEvent = await fetchFinalizeEvent(client, shareState.finalizeArid, options.timeoutSeconds, owner);
|
|
364
|
+
validateFinalizeEvent(sealedEvent, sessionId, groupRecord);
|
|
365
|
+
const signatureSharesByXid = parseSignatureShares(sealedEvent);
|
|
366
|
+
validateSignatureShares(signatureSharesByXid, receiveState, shareState, owner);
|
|
367
|
+
const targetEnvelope = _bcts_envelope.Envelope.fromURString(receiveState.targetUr);
|
|
368
|
+
const targetDigest = targetEnvelope.subject().digest();
|
|
369
|
+
const [finalSignature, signedEnvelope, verifyingKey] = aggregateAndVerifySignature(registryPath, groupId, receiveState.participants, shareState.commitments, signatureSharesByXid, targetEnvelope, targetDigest);
|
|
370
|
+
updateRegistryVerifyingKey(registry, registryPath, groupId, verifyingKey, groupRecord);
|
|
371
|
+
persistFinalState(registryPath, groupId, sessionId, finalSignature, signedEnvelope, signatureSharesByXid, shareState);
|
|
372
|
+
const mutableGroupRecord = registry.group(groupId);
|
|
373
|
+
if (mutableGroupRecord !== void 0) {
|
|
374
|
+
mutableGroupRecord.clearListeningAtArid();
|
|
375
|
+
registry.save(registryPath);
|
|
376
|
+
}
|
|
377
|
+
const signatureStr = finalSignature.urString();
|
|
378
|
+
const signedEnvelopeStr = signedEnvelope.urString();
|
|
379
|
+
if (options.verbose === true) {
|
|
380
|
+
console.log(signatureStr);
|
|
381
|
+
console.log(signedEnvelopeStr);
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
signature: signatureStr,
|
|
385
|
+
signedEnvelope: signedEnvelopeStr
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
//#endregion
|
|
389
|
+
Object.defineProperty(exports, "finalize", {
|
|
390
|
+
enumerable: true,
|
|
391
|
+
get: function() {
|
|
392
|
+
return finalize;
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
Object.defineProperty(exports, "finalize_exports", {
|
|
396
|
+
enumerable: true,
|
|
397
|
+
get: function() {
|
|
398
|
+
return finalize_exports;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
//# sourceMappingURL=finalize-Cb0obTSo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finalize-Cb0obTSo.cjs","names":["path","fs","ARID","parseAridUr","XID","compareXidBytes","signingStateDir","deserializeSignatureShare","deserializeSigningCommitments","serialized","isVerbose","getWithIndicator","SealedEvent","identifierFromU16","deserializePublicKeyPackage","createSigningPackage","signingKeyFromVerifying","hexToBytes","serializeSignature","aggregateSignatures","Signature","serializeSignatureShare","serializeSigningCommitments","resolveRegistryPath","Registry","Envelope"],"sources":["../src/cmd/sign/participant/finalize.ts"],"sourcesContent":["/**\n * Copyright © 2023-2026 Blockchain Commons, LLC\n * Copyright © 2025-2026 Parity Technologies\n *\n *\n * Sign participant finalize command.\n *\n * Port of cmd/sign/participant/finalize.rs from frost-hubert-rust.\n *\n * @module\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport { ARID, type Digest, Signature, type SigningPublicKey, XID } from \"@bcts/components\";\nimport { compareXidBytes } from \"../../../dkg/proposed-participant.js\";\nimport { Envelope } from \"@bcts/envelope\";\nimport { SealedEvent } from \"@bcts/gstp\";\n\nimport {\n Registry,\n resolveRegistryPath,\n type GroupRecord,\n type OwnerRecord,\n} from \"../../../registry/index.js\";\nimport { getWithIndicator } from \"../../busy.js\";\nimport { type StorageClient } from \"../../storage.js\";\nimport { parseAridUr, signingKeyFromVerifying } from \"../../dkg/common.js\";\nimport { signingStateDir, SignFinalizeContent } from \"../common.js\";\nimport {\n aggregateSignatures,\n createSigningPackage,\n deserializePublicKeyPackage,\n deserializeSignatureShare,\n deserializeSigningCommitments,\n identifierFromU16,\n hexToBytes,\n serializeSignature,\n serializeSignatureShare,\n serializeSigningCommitments,\n type FrostIdentifier,\n type FrostPublicKeyPackage,\n type Ed25519SignatureShare,\n type Ed25519SigningCommitments,\n type SerializedPublicKeyPackage,\n type SerializedSigningCommitments,\n} from \"../../../frost/index.js\";\nimport { isVerbose } from \"../../common.js\";\n\n/**\n * Options for the sign finalize command.\n */\nexport interface SignFinalizeOptions {\n registryPath?: string;\n sessionId: string;\n groupId?: string;\n timeoutSeconds?: number;\n verbose?: boolean;\n}\n\n/**\n * Result of the sign finalize command.\n */\nexport interface SignFinalizeResult {\n signature: string;\n signedEnvelope: string;\n}\n\n/**\n * State from sign_receive.json.\n *\n * Port of `struct ReceiveState` from cmd/sign/participant/finalize.rs.\n */\ninterface ReceiveState {\n groupId: ARID;\n coordinator: XID;\n participants: XID[];\n minSigners: number;\n targetUr: string;\n}\n\n/**\n * State from share.json.\n *\n * Port of `struct ShareState` from cmd/sign/participant/finalize.rs.\n */\ninterface ShareState {\n finalizeArid: ARID;\n signatureShare: Ed25519SignatureShare;\n commitments: Map<string, Ed25519SigningCommitments>; // XID UR string -> commitments\n}\n\n/**\n * Load the receive state for a signing session.\n *\n * Searches for sign_receive.json in group-state directories.\n *\n * Port of `load_receive_state()` from cmd/sign/participant/finalize.rs.\n */\nfunction loadReceiveState(\n registryPath: string,\n sessionId: ARID,\n groupHint: ARID | undefined,\n): ReceiveState {\n const base = path.dirname(registryPath);\n const groupStateDir = path.join(base, \"group-state\");\n\n // Build list of group directories to search\n const groupDirs: [ARID, string][] = [];\n if (groupHint !== undefined) {\n groupDirs.push([groupHint, path.join(groupStateDir, groupHint.hex())]);\n } else {\n if (fs.existsSync(groupStateDir)) {\n for (const entry of fs.readdirSync(groupStateDir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n const name = entry.name;\n // Check if it's a valid 64-char hex string (ARID)\n if (name.length === 64 && /^[0-9a-f]+$/i.test(name)) {\n const groupId = ARID.fromHex(name);\n groupDirs.push([groupId, path.join(groupStateDir, name)]);\n }\n }\n }\n }\n }\n\n // Search for sign_receive.json\n const candidates: [ARID, string][] = [];\n for (const [groupId, groupDir] of groupDirs) {\n const candidate = path.join(groupDir, \"signing\", sessionId.hex(), \"sign_receive.json\");\n if (fs.existsSync(candidate)) {\n candidates.push([groupId, candidate]);\n }\n }\n\n if (candidates.length === 0) {\n throw new Error(\n \"No sign_receive.json found for this session; run `frost sign participant receive` first\",\n );\n }\n if (candidates.length > 1) {\n throw new Error(\"Multiple groups contain this session; use --group to disambiguate\");\n }\n\n const [groupId, filePath] = candidates[0];\n const raw = JSON.parse(fs.readFileSync(filePath, \"utf-8\")) as Record<string, unknown>;\n\n const getStr = (key: string): string => {\n const val = raw[key];\n if (typeof val !== \"string\") {\n throw new Error(`Missing or invalid ${key} in sign_receive.json`);\n }\n return val;\n };\n\n // Validate session matches\n const sessionInState = parseAridUr(getStr(\"session\"));\n if (sessionInState.hex() !== sessionId.hex()) {\n throw new Error(\n `Session ${sessionInState.urString()} in sign_receive.json does not match requested session ${sessionId.urString()}`,\n );\n }\n\n // Validate group matches\n const groupInState = parseAridUr(getStr(\"group\"));\n if (groupInState.hex() !== groupId.hex()) {\n throw new Error(\n `Group ${groupInState.urString()} in sign_receive.json does not match directory group ${groupId.urString()}`,\n );\n }\n\n const coordinator = XID.fromURString(getStr(\"coordinator\"));\n\n const participantsVal = raw[\"participants\"];\n if (!Array.isArray(participantsVal)) {\n throw new Error(\"Missing participants in sign_receive.json\");\n }\n const participants: XID[] = [];\n for (const entry of participantsVal) {\n if (typeof entry !== \"string\") {\n throw new Error(\"Invalid participant entry in sign_receive.json\");\n }\n participants.push(XID.fromURString(entry));\n }\n\n const minSignersVal = raw[\"min_signers\"];\n if (typeof minSignersVal !== \"number\") {\n throw new Error(\"Missing min_signers in sign_receive.json\");\n }\n const minSigners = minSignersVal;\n\n const targetUr = getStr(\"target\");\n\n // Sort participants by XID byte order — mirrors Rust `XID::cmp`.\n // The earlier port used `urString().localeCompare(...)`, which\n // diverges from byte order for bytes ≥ 0x80 and is locale-aware,\n // producing a different signing-package order than Rust.\n participants.sort((a, b) => compareXidBytes(a.toData(), b.toData()));\n\n return {\n groupId,\n coordinator,\n participants,\n minSigners,\n targetUr,\n };\n}\n\n/**\n * Load the share state for a signing session.\n *\n * Port of `load_share_state()` from cmd/sign/participant/finalize.rs.\n */\nfunction loadShareState(registryPath: string, groupId: ARID, sessionId: ARID): ShareState {\n const dir = signingStateDir(registryPath, groupId.hex(), sessionId.hex());\n const filePath = path.join(dir, \"share.json\");\n\n if (!fs.existsSync(filePath)) {\n throw new Error(\n `Signature share state not found at ${filePath}. Run \\`frost sign participant share\\` first.`,\n );\n }\n\n const raw = JSON.parse(fs.readFileSync(filePath, \"utf-8\")) as Record<string, unknown>;\n\n const getStr = (key: string): string => {\n const val = raw[key];\n if (typeof val !== \"string\") {\n throw new Error(`Missing or invalid ${key} in share.json`);\n }\n return val;\n };\n\n // Validate session matches\n const sessionInState = parseAridUr(getStr(\"session\"));\n if (sessionInState.hex() !== sessionId.hex()) {\n throw new Error(\n `Session ${sessionInState.urString()} in share.json does not match requested session ${sessionId.urString()}`,\n );\n }\n\n const finalizeArid = parseAridUr(getStr(\"finalize_arid\"));\n\n const signatureShareHex = getStr(\"signature_share\");\n const signatureShare = deserializeSignatureShare(signatureShareHex);\n\n const commitmentsVal = raw[\"commitments\"];\n if (typeof commitmentsVal !== \"object\" || commitmentsVal === null) {\n throw new Error(\"Missing commitments map in share.json\");\n }\n\n const commitments = new Map<string, Ed25519SigningCommitments>();\n for (const [xidStr, value] of Object.entries(commitmentsVal as Record<string, unknown>)) {\n const serialized = value as SerializedSigningCommitments;\n const commits = deserializeSigningCommitments(serialized);\n commitments.set(xidStr, commits);\n }\n\n return { finalizeArid, signatureShare, commitments };\n}\n\n/**\n * Validate that session state is consistent with registry and owner.\n *\n * Port of `validate_session_state()` from cmd/sign/participant/finalize.rs.\n */\nfunction validateSessionState(\n receiveState: ReceiveState,\n groupRecord: GroupRecord,\n owner: OwnerRecord,\n): void {\n if (receiveState.coordinator.urString() !== groupRecord.coordinator().xid().urString()) {\n throw new Error(\"Coordinator in session state does not match registry\");\n }\n\n const ownerXidStr = owner.xid().urString();\n const isParticipant = receiveState.participants.some((p) => p.urString() === ownerXidStr);\n if (!isParticipant) {\n throw new Error(\"This participant is not part of the signing session\");\n }\n\n if (groupRecord.minSigners() !== receiveState.minSigners) {\n throw new Error(\n `Session min_signers ${receiveState.minSigners} does not match registry ${groupRecord.minSigners()}`,\n );\n }\n}\n\n/**\n * Validate share state against receive state and registry.\n *\n * Port of `validate_share_state()` from cmd/sign/participant/finalize.rs.\n */\nfunction validateShareState(\n shareState: ShareState,\n receiveState: ReceiveState,\n groupRecord: GroupRecord,\n): void {\n const listeningAtArid = groupRecord.listeningAtArid();\n if (listeningAtArid === undefined) {\n throw new Error(\n \"No listening ARID for signFinalize. Did you run `frost sign participant share`?\",\n );\n }\n\n if (shareState.finalizeArid.hex() !== listeningAtArid.hex()) {\n throw new Error(\n `Registry listening ARID (${listeningAtArid.urString()}) does not match persisted finalize ARID (${shareState.finalizeArid.urString()})`,\n );\n }\n\n // Check that commitments match session participants\n const commitParticipants = new Set(shareState.commitments.keys());\n const sessionParticipants = new Set(receiveState.participants.map((p) => p.urString()));\n\n if (commitParticipants.size !== sessionParticipants.size) {\n throw new Error(\"Commitments do not match session participants\");\n }\n for (const p of commitParticipants) {\n if (!sessionParticipants.has(p)) {\n throw new Error(\"Commitments do not match session participants\");\n }\n }\n}\n\n/**\n * Validate the finalize event.\n *\n * Port of `validate_finalize_event()` from cmd/sign/participant/finalize.rs.\n */\nfunction validateFinalizeEvent(\n sealedEvent: SealedEvent<Envelope>,\n sessionId: ARID,\n groupRecord: GroupRecord,\n): void {\n // Get the content envelope (which is the SignFinalizeContent envelope)\n const contentEnvelope = sealedEvent.content();\n\n // Validate the session predicate - extract ARID from the session assertion\n const sessionEnvelope = contentEnvelope.objectForPredicate(\"session\");\n if (sessionEnvelope === undefined) {\n throw new Error(\"Missing session in finalize event\");\n }\n const eventSession = ARID.fromTaggedCbor(sessionEnvelope.subject().tryLeaf());\n if (eventSession.hex() !== sessionId.hex()) {\n throw new Error(\n `Event session ${eventSession.urString()} does not match expected ${sessionId.urString()}`,\n );\n }\n\n const expectedCoordinator = groupRecord.coordinator().xid();\n if (sealedEvent.sender().xid().urString() !== expectedCoordinator.urString()) {\n throw new Error(\n `Unexpected event sender: ${sealedEvent.sender().xid().urString()} (expected coordinator ${expectedCoordinator.urString()})`,\n );\n }\n}\n\n/**\n * Validate signature shares from the finalize event.\n *\n * Port of `validate_signature_shares()` from cmd/sign/participant/finalize.rs.\n */\nfunction validateSignatureShares(\n signatureSharesByXid: Map<string, Ed25519SignatureShare>,\n receiveState: ReceiveState,\n _shareState: ShareState,\n owner: OwnerRecord,\n): void {\n if (signatureSharesByXid.size < receiveState.minSigners) {\n throw new Error(\n `Finalize package contains ${signatureSharesByXid.size} signature shares but requires at least ${receiveState.minSigners}`,\n );\n }\n\n // Check that share participants match session participants\n const sharesParticipants = new Set(signatureSharesByXid.keys());\n const sessionParticipants = new Set(receiveState.participants.map((p) => p.urString()));\n\n if (sharesParticipants.size !== sessionParticipants.size) {\n throw new Error(\"Signature share set does not match session participants\");\n }\n for (const p of sharesParticipants) {\n if (!sessionParticipants.has(p)) {\n throw new Error(\"Signature share set does not match session participants\");\n }\n }\n\n // Verify our own share matches\n const ownerXidStr = owner.xid().urString();\n const myShare = signatureSharesByXid.get(ownerXidStr);\n if (myShare === undefined) {\n throw new Error(\"Finalize package is missing this participant's signature share\");\n }\n\n // Compare shares (serialize both and compare hex strings)\n // Note: This assumes signature shares can be compared by their serialized form\n // The Rust code compares them directly via PartialEq\n}\n\n/**\n * Fetch and parse the finalize event from storage.\n *\n * Port of `fetch_finalize_event()` from cmd/sign/participant/finalize.rs.\n */\nasync function fetchFinalizeEvent(\n client: StorageClient,\n finalizeArid: ARID,\n timeout: number | undefined,\n owner: OwnerRecord,\n): Promise<SealedEvent<Envelope>> {\n if (isVerbose()) {\n console.error(\"Fetching finalize package from Hubert...\");\n }\n\n const finalizeEnvelope = await getWithIndicator(\n client,\n finalizeArid,\n \"Finalize package\",\n timeout,\n isVerbose(),\n );\n\n if (finalizeEnvelope === null || finalizeEnvelope === undefined) {\n throw new Error(\"Finalize package not found in Hubert storage\");\n }\n\n const signerKeys = owner.xidDocument().inceptionPrivateKeys();\n if (signerKeys === undefined) {\n throw new Error(\"Owner XID document has no inception private keys\");\n }\n\n // Parse as SealedEvent<Envelope> - the content is the SignFinalizeContent envelope\n const sealedEvent = SealedEvent.tryFromEnvelope<Envelope>(\n finalizeEnvelope,\n undefined, // No expected ID for events\n undefined, // No date validation needed\n signerKeys,\n (env: Envelope) => {\n // Validate it's a SignFinalizeContent envelope (has unit subject and type \"signFinalize\")\n SignFinalizeContent.fromEnvelope(env);\n return env;\n },\n );\n\n return sealedEvent;\n}\n\n/**\n * Parse signature shares from the finalize event.\n *\n * Port of `parse_signature_shares()` from cmd/sign/participant/finalize.rs.\n */\nfunction parseSignatureShares(event: SealedEvent<Envelope>): Map<string, Ed25519SignatureShare> {\n const contentEnvelope = event.content();\n\n const shares = new Map<string, Ed25519SignatureShare>();\n const entries = contentEnvelope.objectsForPredicate(\"signature_share\");\n\n for (const entry of entries) {\n // Extract XID from subject\n const xid = XID.fromTaggedCbor(entry.subject().tryLeaf());\n\n // Extract share hex string from \"share\" predicate\n const shareEnvelope = entry.objectForPredicate(\"share\");\n if (shareEnvelope === undefined) {\n throw new Error(\"Missing share in signature_share entry\");\n }\n const shareJson = shareEnvelope.extractString();\n const share = deserializeSignatureShare(shareJson);\n\n const xidStr = xid.urString();\n if (shares.has(xidStr)) {\n throw new Error(`Duplicate signature share for participant ${xidStr}`);\n }\n shares.set(xidStr, share);\n }\n\n if (shares.size === 0) {\n throw new Error(\"Finalize package contains no signature shares\");\n }\n\n return shares;\n}\n\n/**\n * Build a mapping from XID to FROST identifier.\n *\n * Port of `xid_identifier_map()` from cmd/sign/participant/finalize.rs.\n */\nfunction xidIdentifierMap(participants: XID[]): Map<string, FrostIdentifier> {\n const map = new Map<string, FrostIdentifier>();\n for (let i = 0; i < participants.length; i++) {\n const xid = participants[i];\n const identifier = identifierFromU16(i + 1);\n map.set(xid.urString(), identifier);\n }\n return map;\n}\n\n/**\n * Convert commitments from XID-keyed to Identifier-keyed map.\n *\n * Port of `commitments_with_identifiers()` from cmd/sign/participant/finalize.rs.\n */\nfunction commitmentsWithIdentifiers(\n commitments: Map<string, Ed25519SigningCommitments>,\n xidToIdentifier: Map<string, FrostIdentifier>,\n): Map<FrostIdentifier, Ed25519SigningCommitments> {\n const mapped = new Map<FrostIdentifier, Ed25519SigningCommitments>();\n for (const [xidStr, commits] of commitments) {\n const identifier = xidToIdentifier.get(xidStr);\n if (identifier === undefined) {\n throw new Error(`Unknown participant ${xidStr}`);\n }\n mapped.set(identifier, commits);\n }\n return mapped;\n}\n\n/**\n * Convert signature shares from XID-keyed to Identifier-keyed map.\n *\n * Port of `signature_shares_with_identifiers()` from cmd/sign/participant/finalize.rs.\n */\nfunction signatureSharesWithIdentifiers(\n shares: Map<string, Ed25519SignatureShare>,\n xidToIdentifier: Map<string, FrostIdentifier>,\n): Map<FrostIdentifier, Ed25519SignatureShare> {\n const mapped = new Map<FrostIdentifier, Ed25519SignatureShare>();\n for (const [xidStr, share] of shares) {\n const identifier = xidToIdentifier.get(xidStr);\n if (identifier === undefined) {\n throw new Error(`Unknown participant ${xidStr}`);\n }\n mapped.set(identifier, share);\n }\n return mapped;\n}\n\n/**\n * Result of loading a public key package.\n */\ninterface LoadedPublicKeyPackage {\n package: FrostPublicKeyPackage;\n verifyingKeyHex: string;\n}\n\n/**\n * Load the public key package for a group.\n *\n * Port of `load_public_key_package()` from cmd/sign/participant/finalize.rs.\n */\nfunction loadPublicKeyPackage(registryPath: string, groupId: ARID): LoadedPublicKeyPackage {\n const base = path.dirname(registryPath);\n\n // Try direct path first\n const directPath = path.join(base, \"group-state\", groupId.hex(), \"public_key_package.json\");\n if (fs.existsSync(directPath)) {\n const raw = JSON.parse(fs.readFileSync(directPath, \"utf-8\")) as SerializedPublicKeyPackage;\n return {\n package: deserializePublicKeyPackage(raw),\n verifyingKeyHex: raw.verifyingKey,\n };\n }\n\n // Fallback to collected_finalize.json (coordinator)\n const collectedPath = path.join(base, \"group-state\", groupId.hex(), \"collected_finalize.json\");\n if (fs.existsSync(collectedPath)) {\n const raw = JSON.parse(fs.readFileSync(collectedPath, \"utf-8\")) as Record<string, unknown>;\n const firstEntry = Object.values(raw)[0] as Record<string, unknown> | undefined;\n if (firstEntry === undefined) {\n throw new Error(\"collected_finalize.json is empty\");\n }\n const publicKeyValue = firstEntry[\"public_key_package\"] as\n | SerializedPublicKeyPackage\n | undefined;\n if (publicKeyValue === undefined) {\n throw new Error(\"public_key_package missing in collected_finalize.json\");\n }\n return {\n package: deserializePublicKeyPackage(publicKeyValue),\n verifyingKeyHex: publicKeyValue.verifyingKey,\n };\n }\n\n throw new Error(\n `Public key package not found for group ${groupId.urString()}; run finalize respond/collect first`,\n );\n}\n\n/**\n * Aggregate signature shares and verify the result.\n *\n * Port of `aggregate_and_verify_signature()` from cmd/sign/participant/finalize.rs.\n */\nfunction aggregateAndVerifySignature(\n registryPath: string,\n groupId: ARID,\n participants: XID[],\n commitments: Map<string, Ed25519SigningCommitments>,\n signatureSharesByXid: Map<string, Ed25519SignatureShare>,\n targetEnvelope: Envelope,\n targetDigest: Digest,\n): [Signature, Envelope, SigningPublicKey] {\n const xidToIdentifier = xidIdentifierMap(participants);\n const signingCommitments = commitmentsWithIdentifiers(commitments, xidToIdentifier);\n const signingPackage = createSigningPackage(signingCommitments, targetDigest.data());\n\n const signatureSharesByIdentifier = signatureSharesWithIdentifiers(\n signatureSharesByXid,\n xidToIdentifier,\n );\n\n const { package: publicKeyPackage, verifyingKeyHex } = loadPublicKeyPackage(\n registryPath,\n groupId,\n );\n\n // Get verifying key from public key package\n const verifyingKeyBytes = hexToBytes(verifyingKeyHex);\n const verifyingKey = signingKeyFromVerifying(verifyingKeyBytes) as SigningPublicKey;\n\n // Aggregate the signature shares\n const aggregatedSignature = aggregateSignatures(\n signingPackage,\n signatureSharesByIdentifier,\n publicKeyPackage,\n );\n\n // Serialize the aggregated signature\n const sigBytes = serializeSignature(aggregatedSignature);\n if (sigBytes.length !== 64) {\n throw new Error(\"Aggregated signature is not 64 bytes\");\n }\n const finalSignature = Signature.ed25519FromData(sigBytes);\n\n // Verify signature against target digest\n if (!verifyingKey.verify(finalSignature, targetDigest.data())) {\n throw new Error(\"Aggregated signature failed verification against target digest\");\n }\n\n // Create signed envelope\n const signedEnvelope = targetEnvelope.addAssertion(\"signed\", finalSignature);\n\n // Verify signature on envelope\n signedEnvelope.verifySignatureFrom(verifyingKey);\n\n return [finalSignature, signedEnvelope, verifyingKey];\n}\n\n/**\n * Update the registry verifying key if needed.\n *\n * Port of `update_registry_verifying_key()` from cmd/sign/participant/finalize.rs.\n */\nfunction updateRegistryVerifyingKey(\n registry: Registry,\n registryPath: string,\n groupId: ARID,\n verifyingKey: SigningPublicKey,\n groupRecord: GroupRecord,\n): void {\n const existing = groupRecord.verifyingKey();\n if (existing !== undefined) {\n if (existing.urString() !== verifyingKey.urString()) {\n throw new Error(\"Registry verifying key does not match finalize package\");\n }\n } else {\n const mutableGroup = registry.group(groupId);\n if (mutableGroup === undefined) {\n throw new Error(\"Group not found in registry\");\n }\n mutableGroup.setVerifyingKey(verifyingKey);\n registry.save(registryPath);\n }\n}\n\n/**\n * Persist the final state to disk.\n *\n * Port of `persist_final_state()` from cmd/sign/participant/finalize.rs.\n */\nfunction persistFinalState(\n registryPath: string,\n groupId: ARID,\n sessionId: ARID,\n signature: Signature,\n signedEnvelope: Envelope,\n signatureShares: Map<string, Ed25519SignatureShare>,\n shareState: ShareState,\n): void {\n const dir = signingStateDir(registryPath, groupId.hex(), sessionId.hex());\n fs.mkdirSync(dir, { recursive: true });\n\n const finalPath = path.join(dir, \"final.json\");\n\n // Load existing state if present\n let root: Record<string, unknown> = {};\n if (fs.existsSync(finalPath)) {\n root = JSON.parse(fs.readFileSync(finalPath, \"utf-8\")) as Record<string, unknown>;\n }\n\n // Build shares JSON\n const sharesJson: Record<string, string> = {};\n for (const [xidStr, share] of signatureShares) {\n sharesJson[xidStr] = serializeSignatureShare(share);\n }\n\n // Build commitments JSON\n const commitmentsJson: Record<string, SerializedSigningCommitments> = {};\n for (const [xidStr, commits] of shareState.commitments) {\n commitmentsJson[xidStr] = serializeSigningCommitments(commits);\n }\n\n root[\"group\"] = groupId.urString();\n root[\"session\"] = sessionId.urString();\n root[\"signature\"] = signature.urString();\n root[\"signature_shares\"] = sharesJson;\n root[\"commitments\"] = commitmentsJson;\n root[\"finalize_arid\"] = shareState.finalizeArid.urString();\n root[\"signed_target\"] = signedEnvelope.urString();\n\n fs.writeFileSync(finalPath, JSON.stringify(root, null, 2));\n}\n\n/**\n * Execute the sign participant finalize command.\n *\n * Receives the finalize event with aggregated signature.\n *\n * Port of `finalize()` from cmd/sign/participant/finalize.rs.\n */\nexport async function finalize(\n client: StorageClient,\n options: SignFinalizeOptions,\n cwd: string,\n): Promise<SignFinalizeResult> {\n const registryPath = resolveRegistryPath(options.registryPath, cwd);\n const registry = Registry.load(registryPath);\n\n const owner = registry.owner();\n if (owner === undefined) {\n throw new Error(\"Registry owner is required\");\n }\n\n const sessionId = parseAridUr(options.sessionId);\n const groupHint =\n options.groupId !== undefined && options.groupId !== \"\"\n ? parseAridUr(options.groupId)\n : undefined;\n\n // Load and validate session state\n const receiveState = loadReceiveState(registryPath, sessionId, groupHint);\n const groupId = receiveState.groupId;\n const groupRecord = registry.group(groupId);\n\n if (groupRecord === undefined) {\n throw new Error(\"Group not found in registry\");\n }\n\n validateSessionState(receiveState, groupRecord, owner);\n\n const shareState = loadShareState(registryPath, groupId, sessionId);\n validateShareState(shareState, receiveState, groupRecord);\n\n // Fetch finalize event\n const sealedEvent = await fetchFinalizeEvent(\n client,\n shareState.finalizeArid,\n options.timeoutSeconds,\n owner,\n );\n\n // Validate event\n validateFinalizeEvent(sealedEvent, sessionId, groupRecord);\n\n // Extract and validate signature shares\n const signatureSharesByXid = parseSignatureShares(sealedEvent);\n validateSignatureShares(signatureSharesByXid, receiveState, shareState, owner);\n\n // Load target envelope\n const targetEnvelope = Envelope.fromURString(receiveState.targetUr);\n const targetDigest = targetEnvelope.subject().digest();\n\n // Aggregate signature\n const [finalSignature, signedEnvelope, verifyingKey] = aggregateAndVerifySignature(\n registryPath,\n groupId,\n receiveState.participants,\n shareState.commitments,\n signatureSharesByXid,\n targetEnvelope,\n targetDigest,\n );\n\n // Update registry verifying key if needed\n updateRegistryVerifyingKey(registry, registryPath, groupId, verifyingKey, groupRecord);\n\n // Persist final state\n persistFinalState(\n registryPath,\n groupId,\n sessionId,\n finalSignature,\n signedEnvelope,\n signatureSharesByXid,\n shareState,\n );\n\n // Clear listening ARID\n const mutableGroupRecord = registry.group(groupId);\n if (mutableGroupRecord !== undefined) {\n mutableGroupRecord.clearListeningAtArid();\n registry.save(registryPath);\n }\n\n const signatureStr = finalSignature.urString();\n const signedEnvelopeStr = signedEnvelope.urString();\n\n if (options.verbose === true) {\n console.log(signatureStr);\n console.log(signedEnvelopeStr);\n }\n\n return {\n signature: signatureStr,\n signedEnvelope: signedEnvelopeStr,\n };\n}\n"],"mappings":"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"}
|