@bcts/frost-hubert 1.0.0-alpha.22 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/frost.cjs +347 -75
- package/dist/bin/frost.cjs.map +1 -1
- package/dist/bin/frost.mjs +347 -75
- package/dist/bin/frost.mjs.map +1 -1
- package/dist/busy-DkM2jAIZ.mjs +27 -0
- package/dist/busy-DkM2jAIZ.mjs.map +1 -0
- package/dist/busy-EZU7EKr6.cjs +38 -0
- package/dist/busy-EZU7EKr6.cjs.map +1 -0
- package/dist/{chunk-uaV2rQ02.cjs → chunk-CZWwpsFl.cjs} +22 -32
- package/dist/{chunk-ClPoSABd.mjs → chunk-CjcI7cDX.mjs} +6 -12
- package/dist/cmd/index.cjs +46 -43
- package/dist/cmd/index.d.cts +2 -4
- package/dist/cmd/index.d.mts +2 -4
- package/dist/cmd/index.mjs +7 -6
- package/dist/cmd-Bw9_i2_f.cjs +130 -0
- package/dist/cmd-Bw9_i2_f.cjs.map +1 -0
- package/dist/cmd-CS1uJtuD.mjs +113 -0
- package/dist/cmd-CS1uJtuD.mjs.map +1 -0
- package/dist/common-CvH6dFvQ.mjs +282 -0
- package/dist/common-CvH6dFvQ.mjs.map +1 -0
- package/dist/common-DUWvtc08.mjs +96 -0
- package/dist/common-DUWvtc08.mjs.map +1 -0
- package/dist/common-lKP5EzHy.cjs +372 -0
- package/dist/common-lKP5EzHy.cjs.map +1 -0
- package/dist/common-lThIvJmZ.cjs +114 -0
- package/dist/common-lThIvJmZ.cjs.map +1 -0
- package/dist/dkg/index.cjs +245 -7
- package/dist/dkg/index.cjs.map +1 -0
- package/dist/dkg/index.d.cts +2 -2
- package/dist/dkg/index.d.mts +2 -2
- package/dist/dkg/index.mjs +238 -2
- package/dist/dkg/index.mjs.map +1 -0
- package/dist/finalize-BRgJK-Xv.cjs +402 -0
- package/dist/finalize-BRgJK-Xv.cjs.map +1 -0
- package/dist/finalize-BfLgzn8f.cjs +303 -0
- package/dist/finalize-BfLgzn8f.cjs.map +1 -0
- package/dist/finalize-CNTDj6aS.mjs +389 -0
- package/dist/finalize-CNTDj6aS.mjs.map +1 -0
- package/dist/finalize-EC3ikHQq.mjs +252 -0
- package/dist/finalize-EC3ikHQq.mjs.map +1 -0
- package/dist/finalize-IA01t_Qq.mjs +290 -0
- package/dist/finalize-IA01t_Qq.mjs.map +1 -0
- package/dist/finalize-UPyI1yb1.cjs +265 -0
- package/dist/finalize-UPyI1yb1.cjs.map +1 -0
- package/dist/frost/index.cjs +8 -9
- package/dist/frost/index.cjs.map +1 -1
- package/dist/frost/index.mjs +2 -3
- package/dist/frost/index.mjs.map +1 -1
- package/dist/{group-invite-Dz1Jmiky.d.cts → index-B3c-80VS.d.cts} +25 -2
- package/dist/index-B3c-80VS.d.cts.map +1 -0
- package/dist/{index-CcvTi5EA.d.cts → index-BgbSGpxn.d.mts} +102 -80
- package/dist/index-BgbSGpxn.d.mts.map +1 -0
- package/dist/{registry-impl-CE76sTXQ.d.cts → index-C8QeHNwa.d.cts} +46 -2
- package/dist/index-C8QeHNwa.d.cts.map +1 -0
- package/dist/{group-invite-Wk9CIbHL.d.mts → index-D3QTWkEm.d.mts} +25 -2
- package/dist/index-D3QTWkEm.d.mts.map +1 -0
- package/dist/{registry-impl-BETn_lEO.d.mts → index-DVbWyOs7.d.mts} +46 -2
- package/dist/index-DVbWyOs7.d.mts.map +1 -0
- package/dist/{index-DNCPeLNM.d.mts → index-F1iNEAJR.d.cts} +102 -80
- package/dist/index-F1iNEAJR.d.cts.map +1 -0
- package/dist/index.cjs +72 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11 -10
- package/dist/index.mjs.map +1 -1
- package/dist/invite-5277FQVT.cjs +274 -0
- package/dist/invite-5277FQVT.cjs.map +1 -0
- package/dist/invite-DUTcfTgX.cjs +109 -0
- package/dist/invite-DUTcfTgX.cjs.map +1 -0
- package/dist/invite-IU4n0dq2.mjs +96 -0
- package/dist/invite-IU4n0dq2.mjs.map +1 -0
- package/dist/invite-RU-OXTNS.mjs +219 -0
- package/dist/invite-RU-OXTNS.mjs.map +1 -0
- package/dist/parallel-D1R6ZGlY.cjs +318 -0
- package/dist/parallel-D1R6ZGlY.cjs.map +1 -0
- package/dist/parallel-D6zc6VW4.mjs +235 -0
- package/dist/parallel-D6zc6VW4.mjs.map +1 -0
- package/dist/proposed-participant-Dm1Eq6mX.cjs +141 -0
- package/dist/proposed-participant-Dm1Eq6mX.cjs.map +1 -0
- package/dist/proposed-participant-cWM7iUrO.mjs +129 -0
- package/dist/proposed-participant-cWM7iUrO.mjs.map +1 -0
- package/dist/receive-CAI-x4II.cjs +213 -0
- package/dist/receive-CAI-x4II.cjs.map +1 -0
- package/dist/receive-D2Nn68L7.mjs +188 -0
- package/dist/receive-D2Nn68L7.mjs.map +1 -0
- package/dist/receive-DA_KQEgk.mjs +177 -0
- package/dist/receive-DA_KQEgk.mjs.map +1 -0
- package/dist/receive-kZMsXhbK.cjs +190 -0
- package/dist/receive-kZMsXhbK.cjs.map +1 -0
- package/dist/registry/index.cjs +881 -13
- package/dist/registry/index.cjs.map +1 -0
- package/dist/registry/index.d.cts +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +867 -2
- package/dist/registry/index.mjs.map +1 -0
- package/dist/{registry-FMU-ec5K.cjs → registry-9puTaRrD.cjs} +28 -31
- package/dist/registry-9puTaRrD.cjs.map +1 -0
- package/dist/{registry-BDnNV1Rk.mjs → registry-BpCwtrRt.mjs} +7 -10
- package/dist/{registry-BDnNV1Rk.mjs.map → registry-BpCwtrRt.mjs.map} +1 -1
- package/dist/round1-4Hyx8w0x.cjs +422 -0
- package/dist/round1-4Hyx8w0x.cjs.map +1 -0
- package/dist/round1-7v9LlE11.mjs +373 -0
- package/dist/round1-7v9LlE11.mjs.map +1 -0
- package/dist/round1-BHBjru1m.cjs +465 -0
- package/dist/round1-BHBjru1m.cjs.map +1 -0
- package/dist/round1-CMLKN2RR.mjs +195 -0
- package/dist/round1-CMLKN2RR.mjs.map +1 -0
- package/dist/round1-CWSXZx5R.cjs +208 -0
- package/dist/round1-CWSXZx5R.cjs.map +1 -0
- package/dist/round1-CcQCGlIT.mjs +208 -0
- package/dist/round1-CcQCGlIT.mjs.map +1 -0
- package/dist/round1-Cgm7j1kI.mjs +452 -0
- package/dist/round1-Cgm7j1kI.mjs.map +1 -0
- package/dist/round1-DQ0fnc1H.cjs +221 -0
- package/dist/round1-DQ0fnc1H.cjs.map +1 -0
- package/dist/round2-BWz9SQIi.cjs +305 -0
- package/dist/round2-BWz9SQIi.cjs.map +1 -0
- package/dist/round2-BkNRCXgS.mjs +292 -0
- package/dist/round2-BkNRCXgS.mjs.map +1 -0
- package/dist/round2-Bl2uK93U.mjs +450 -0
- package/dist/round2-Bl2uK93U.mjs.map +1 -0
- package/dist/round2-CdUT-AhH.cjs +499 -0
- package/dist/round2-CdUT-AhH.cjs.map +1 -0
- package/dist/round2-DOA3rnV-.mjs +280 -0
- package/dist/round2-DOA3rnV-.mjs.map +1 -0
- package/dist/round2-Dg24w-TU.mjs +397 -0
- package/dist/round2-Dg24w-TU.mjs.map +1 -0
- package/dist/round2-LylCa84n.cjs +293 -0
- package/dist/round2-LylCa84n.cjs.map +1 -0
- package/dist/round2-o2Q-GMbX.cjs +410 -0
- package/dist/round2-o2Q-GMbX.cjs.map +1 -0
- package/dist/storage-B-Gu68-O.cjs +79 -0
- package/dist/storage-B-Gu68-O.cjs.map +1 -0
- package/dist/storage-Bkkliz0K.mjs +74 -0
- package/dist/storage-Bkkliz0K.mjs.map +1 -0
- package/package.json +17 -17
- 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 +52 -18
- 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 +33 -5
- package/src/frost/index.ts +1 -1
- package/src/registry/owner-record.ts +13 -2
- package/src/registry/participant-record.ts +36 -4
- package/src/registry/registry-impl.ts +74 -18
- package/dist/group-invite-CrbOabFL.cjs +0 -368
- package/dist/group-invite-CrbOabFL.cjs.map +0 -1
- package/dist/group-invite-Dz1Jmiky.d.cts.map +0 -1
- package/dist/group-invite-RPElq-fm.mjs +0 -338
- package/dist/group-invite-RPElq-fm.mjs.map +0 -1
- package/dist/group-invite-Wk9CIbHL.d.mts.map +0 -1
- package/dist/index-CcvTi5EA.d.cts.map +0 -1
- package/dist/index-DNCPeLNM.d.mts.map +0 -1
- package/dist/registry-FMU-ec5K.cjs.map +0 -1
- package/dist/registry-impl-BETn_lEO.d.mts.map +0 -1
- package/dist/registry-impl-C7w4awTv.cjs +0 -865
- package/dist/registry-impl-C7w4awTv.cjs.map +0 -1
- package/dist/registry-impl-CE76sTXQ.d.cts.map +0 -1
- package/dist/registry-impl-eYXVSPwM.mjs +0 -797
- package/dist/registry-impl-eYXVSPwM.mjs.map +0 -1
- package/dist/sign-2bOp18Fs.cjs +0 -4875
- package/dist/sign-2bOp18Fs.cjs.map +0 -1
- package/dist/sign-D8C3HJ4B.mjs +0 -4736
- package/dist/sign-D8C3HJ4B.mjs.map +0 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
//#region src/cmd/parallel.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a Pending status.
|
|
4
|
+
*/
|
|
5
|
+
function fetchStatusPending() {
|
|
6
|
+
return { type: "Pending" };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a Success status.
|
|
10
|
+
*/
|
|
11
|
+
function fetchStatusSuccess(envelope) {
|
|
12
|
+
return {
|
|
13
|
+
type: "Success",
|
|
14
|
+
envelope
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a Rejected status.
|
|
19
|
+
*/
|
|
20
|
+
function fetchStatusRejected(reason) {
|
|
21
|
+
return {
|
|
22
|
+
type: "Rejected",
|
|
23
|
+
reason
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create an Error status.
|
|
28
|
+
*/
|
|
29
|
+
function fetchStatusError(error) {
|
|
30
|
+
return {
|
|
31
|
+
type: "Error",
|
|
32
|
+
error
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a Timeout status.
|
|
37
|
+
*/
|
|
38
|
+
function fetchStatusTimeout() {
|
|
39
|
+
return { type: "Timeout" };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Direction of the operation (get or put).
|
|
43
|
+
*
|
|
44
|
+
* Port of `enum Direction` from cmd/parallel.rs.
|
|
45
|
+
*/
|
|
46
|
+
let Direction = /* @__PURE__ */ function(Direction) {
|
|
47
|
+
/** Downloading from storage */
|
|
48
|
+
Direction["Get"] = "Get";
|
|
49
|
+
/** Uploading to storage */
|
|
50
|
+
Direction["Put"] = "Put";
|
|
51
|
+
return Direction;
|
|
52
|
+
}({});
|
|
53
|
+
/**
|
|
54
|
+
* Get the emoji for a direction.
|
|
55
|
+
*
|
|
56
|
+
* Port of `Direction::emoji()` from cmd/parallel.rs.
|
|
57
|
+
*/
|
|
58
|
+
function directionEmoji(direction) {
|
|
59
|
+
switch (direction) {
|
|
60
|
+
case "Get": return "⬇️";
|
|
61
|
+
case "Put": return "⬆️";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Default timeout in seconds (10 minutes).
|
|
66
|
+
*/
|
|
67
|
+
const DEFAULT_TIMEOUT_SECONDS = 600;
|
|
68
|
+
/**
|
|
69
|
+
* Create a config with the specified timeout.
|
|
70
|
+
*/
|
|
71
|
+
function parallelFetchConfigWithTimeout(timeoutSeconds) {
|
|
72
|
+
return { timeoutSeconds };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Result of collecting responses from multiple participants.
|
|
76
|
+
*
|
|
77
|
+
* Port of `struct CollectionResult` from cmd/parallel.rs.
|
|
78
|
+
*/
|
|
79
|
+
var CollectionResult = class {
|
|
80
|
+
/** Successful responses as [XID, T] tuples */
|
|
81
|
+
successes;
|
|
82
|
+
/** Participants who explicitly rejected as [XID, reason] tuples */
|
|
83
|
+
rejections;
|
|
84
|
+
/** Participants with network/parsing errors as [XID, error] tuples */
|
|
85
|
+
errors;
|
|
86
|
+
/** Participants who timed out */
|
|
87
|
+
timeouts;
|
|
88
|
+
constructor() {
|
|
89
|
+
this.successes = [];
|
|
90
|
+
this.rejections = [];
|
|
91
|
+
this.errors = [];
|
|
92
|
+
this.timeouts = [];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if enough responses were received to proceed.
|
|
96
|
+
*
|
|
97
|
+
* Port of `CollectionResult::can_proceed()` from cmd/parallel.rs.
|
|
98
|
+
*/
|
|
99
|
+
canProceed(minRequired) {
|
|
100
|
+
return this.successes.length >= minRequired;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Total number of participants.
|
|
104
|
+
*
|
|
105
|
+
* Port of `CollectionResult::total()` from cmd/parallel.rs.
|
|
106
|
+
*/
|
|
107
|
+
total() {
|
|
108
|
+
return this.successes.length + this.rejections.length + this.errors.length + this.timeouts.length;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if all responses succeeded.
|
|
112
|
+
*
|
|
113
|
+
* Port of `CollectionResult::all_succeeded()` from cmd/parallel.rs.
|
|
114
|
+
*/
|
|
115
|
+
allSucceeded() {
|
|
116
|
+
return this.rejections.length === 0 && this.errors.length === 0 && this.timeouts.length === 0;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Create an empty collection result.
|
|
121
|
+
*/
|
|
122
|
+
function emptyCollectionResult() {
|
|
123
|
+
return new CollectionResult();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Helper to build request tuples from pending requests and registry.
|
|
127
|
+
*
|
|
128
|
+
* Port of `build_fetch_requests()` from cmd/parallel.rs.
|
|
129
|
+
*/
|
|
130
|
+
function buildFetchRequests(pending, getName) {
|
|
131
|
+
const requests = [];
|
|
132
|
+
for (const [xid, arid] of pending) {
|
|
133
|
+
const name = getName(xid);
|
|
134
|
+
requests.push([
|
|
135
|
+
xid,
|
|
136
|
+
arid,
|
|
137
|
+
name
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
return requests;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Simple progress output for non-interactive terminals.
|
|
144
|
+
*/
|
|
145
|
+
function logProgress(direction, name, status, message) {
|
|
146
|
+
const emoji = directionEmoji(direction);
|
|
147
|
+
switch (status) {
|
|
148
|
+
case "success":
|
|
149
|
+
console.error(`${emoji} ✅ ${name}`);
|
|
150
|
+
break;
|
|
151
|
+
case "error":
|
|
152
|
+
console.error(`${emoji} ❌ ${name}: ${message ?? "Error"}`);
|
|
153
|
+
break;
|
|
154
|
+
case "timeout":
|
|
155
|
+
console.error(`${emoji} ❌ ${name}: Timeout`);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Fetch messages from multiple ARIDs in parallel.
|
|
161
|
+
*
|
|
162
|
+
* Port of `parallel_fetch()` from cmd/parallel.rs.
|
|
163
|
+
*/
|
|
164
|
+
async function parallelFetch(client, requests, validate, config) {
|
|
165
|
+
const result = new CollectionResult();
|
|
166
|
+
const timeoutSeconds = config.timeoutSeconds ?? 600;
|
|
167
|
+
if (config.verbose === true) console.error(`Waiting for ${requests.length} responses...`);
|
|
168
|
+
const promises = requests.map(async ([xid, arid, name]) => {
|
|
169
|
+
try {
|
|
170
|
+
const envelope = await client.get(arid, timeoutSeconds);
|
|
171
|
+
if (!envelope) {
|
|
172
|
+
result.timeouts.push(xid);
|
|
173
|
+
if (config.verbose === true) logProgress("Get", name, "timeout");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const parsed = validate(envelope, xid);
|
|
177
|
+
if (parsed !== null && typeof parsed === "object" && "rejected" in parsed) {
|
|
178
|
+
result.rejections.push([xid, parsed.rejected]);
|
|
179
|
+
if (config.verbose === true) logProgress("Get", name, "error", parsed.rejected);
|
|
180
|
+
} else {
|
|
181
|
+
result.successes.push([xid, parsed]);
|
|
182
|
+
if (config.verbose === true) logProgress("Get", name, "success");
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
186
|
+
if (errorMessage.includes("Timeout") || errorMessage.includes("timeout")) {
|
|
187
|
+
result.timeouts.push(xid);
|
|
188
|
+
if (config.verbose === true) logProgress("Get", name, "timeout");
|
|
189
|
+
} else {
|
|
190
|
+
result.errors.push([xid, `${name}: ${errorMessage}`]);
|
|
191
|
+
if (config.verbose === true) logProgress("Get", name, "error", errorMessage);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
await Promise.all(promises);
|
|
196
|
+
if (config.verbose === true) {
|
|
197
|
+
console.error(`Collected ${result.successes.length} responses`);
|
|
198
|
+
if (result.rejections.length > 0) console.error(` ${result.rejections.length} rejections`);
|
|
199
|
+
if (result.errors.length > 0) console.error(` ${result.errors.length} errors`);
|
|
200
|
+
if (result.timeouts.length > 0) console.error(` ${result.timeouts.length} timeouts`);
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Send messages to multiple ARIDs in parallel.
|
|
206
|
+
*
|
|
207
|
+
* Port of `parallel_send()` from cmd/parallel.rs.
|
|
208
|
+
*/
|
|
209
|
+
async function parallelSend(client, messages, verbose) {
|
|
210
|
+
const results = [];
|
|
211
|
+
if (verbose === true) console.error(`Sending to ${messages.length} participants...`);
|
|
212
|
+
const promises = messages.map(async ([xid, arid, envelope, name]) => {
|
|
213
|
+
try {
|
|
214
|
+
await client.put(arid, envelope);
|
|
215
|
+
results.push([xid, null]);
|
|
216
|
+
if (verbose === true) logProgress("Put", name, "success");
|
|
217
|
+
} catch (error) {
|
|
218
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
219
|
+
results.push([xid, err]);
|
|
220
|
+
if (verbose === true) logProgress("Put", name, "error", err.message);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
await Promise.all(promises);
|
|
224
|
+
if (verbose === true) {
|
|
225
|
+
const successes = results.filter(([_, err]) => err === null).length;
|
|
226
|
+
const failures = results.length - successes;
|
|
227
|
+
console.error(`Sent ${successes} messages`);
|
|
228
|
+
if (failures > 0) console.error(` ${failures} failed`);
|
|
229
|
+
}
|
|
230
|
+
return results;
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
export { directionEmoji as a, fetchStatusPending as c, fetchStatusTimeout as d, parallelFetch as f, buildFetchRequests as i, fetchStatusRejected as l, parallelSend as m, DEFAULT_TIMEOUT_SECONDS as n, emptyCollectionResult as o, parallelFetchConfigWithTimeout as p, Direction as r, fetchStatusError as s, CollectionResult as t, fetchStatusSuccess as u };
|
|
234
|
+
|
|
235
|
+
//# sourceMappingURL=parallel-D6zc6VW4.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel-D6zc6VW4.mjs","names":[],"sources":["../src/cmd/parallel.ts"],"sourcesContent":["/**\n * Copyright © 2023-2026 Blockchain Commons, LLC\n * Copyright © 2025-2026 Parity Technologies\n *\n *\n * Parallel fetch and send utilities for coordinator commands.\n *\n * This module provides utilities for fetching responses from multiple\n * participants in parallel with progress display.\n *\n * Port of cmd/parallel.rs from frost-hubert-rust.\n *\n * @module\n */\n\nimport { type ARID, type XID } from \"@bcts/components\";\nimport { type Envelope } from \"@bcts/envelope\";\n\nimport { type StorageClient } from \"./storage.js\";\n\n/**\n * Status of a participant's response fetch.\n *\n * Port of `enum FetchStatus` from cmd/parallel.rs.\n */\nexport type FetchStatus =\n | { type: \"Pending\" }\n | { type: \"Success\"; envelope: Envelope }\n | { type: \"Rejected\"; reason: string }\n | { type: \"Error\"; error: string }\n | { type: \"Timeout\" };\n\n/**\n * Create a Pending status.\n */\nexport function fetchStatusPending(): FetchStatus {\n return { type: \"Pending\" };\n}\n\n/**\n * Create a Success status.\n */\nexport function fetchStatusSuccess(envelope: Envelope): FetchStatus {\n return { type: \"Success\", envelope };\n}\n\n/**\n * Create a Rejected status.\n */\nexport function fetchStatusRejected(reason: string): FetchStatus {\n return { type: \"Rejected\", reason };\n}\n\n/**\n * Create an Error status.\n */\nexport function fetchStatusError(error: string): FetchStatus {\n return { type: \"Error\", error };\n}\n\n/**\n * Create a Timeout status.\n */\nexport function fetchStatusTimeout(): FetchStatus {\n return { type: \"Timeout\" };\n}\n\n/**\n * Direction of the operation (get or put).\n *\n * Port of `enum Direction` from cmd/parallel.rs.\n */\nexport enum Direction {\n /** Downloading from storage */\n Get = \"Get\",\n /** Uploading to storage */\n Put = \"Put\",\n}\n\n/**\n * Get the emoji for a direction.\n *\n * Port of `Direction::emoji()` from cmd/parallel.rs.\n */\nexport function directionEmoji(direction: Direction): string {\n switch (direction) {\n case Direction.Get:\n return \"⬇️\";\n case Direction.Put:\n return \"⬆️\";\n }\n}\n\n/**\n * Configuration for parallel fetch operations.\n *\n * Port of `struct ParallelFetchConfig` from cmd/parallel.rs.\n */\nexport interface ParallelFetchConfig {\n /** Maximum time to wait for all responses (in seconds) */\n timeoutSeconds?: number | undefined;\n /** Whether to show verbose output */\n verbose?: boolean | undefined;\n}\n\n/**\n * Default timeout in seconds (10 minutes).\n */\nexport const DEFAULT_TIMEOUT_SECONDS = 600;\n\n/**\n * Create a config with the specified timeout.\n */\nexport function parallelFetchConfigWithTimeout(timeoutSeconds?: number): ParallelFetchConfig {\n return { timeoutSeconds };\n}\n\n/**\n * Result of collecting responses from multiple participants.\n *\n * Port of `struct CollectionResult` from cmd/parallel.rs.\n */\nexport class CollectionResult<T> {\n /** Successful responses as [XID, T] tuples */\n successes: [XID, T][];\n /** Participants who explicitly rejected as [XID, reason] tuples */\n rejections: [XID, string][];\n /** Participants with network/parsing errors as [XID, error] tuples */\n errors: [XID, string][];\n /** Participants who timed out */\n timeouts: XID[];\n\n constructor() {\n this.successes = [];\n this.rejections = [];\n this.errors = [];\n this.timeouts = [];\n }\n\n /**\n * Check if enough responses were received to proceed.\n *\n * Port of `CollectionResult::can_proceed()` from cmd/parallel.rs.\n */\n canProceed(minRequired: number): boolean {\n return this.successes.length >= minRequired;\n }\n\n /**\n * Total number of participants.\n *\n * Port of `CollectionResult::total()` from cmd/parallel.rs.\n */\n total(): number {\n return (\n this.successes.length + this.rejections.length + this.errors.length + this.timeouts.length\n );\n }\n\n /**\n * Check if all responses succeeded.\n *\n * Port of `CollectionResult::all_succeeded()` from cmd/parallel.rs.\n */\n allSucceeded(): boolean {\n return this.rejections.length === 0 && this.errors.length === 0 && this.timeouts.length === 0;\n }\n}\n\n/**\n * Create an empty collection result.\n */\nexport function emptyCollectionResult<T>(): CollectionResult<T> {\n return new CollectionResult<T>();\n}\n\n/**\n * Helper to build request tuples from pending requests and registry.\n *\n * Port of `build_fetch_requests()` from cmd/parallel.rs.\n */\nexport function buildFetchRequests(\n pending: Iterable<[XID, ARID]>,\n getName: (xid: XID) => string,\n): [XID, ARID, string][] {\n const requests: [XID, ARID, string][] = [];\n for (const [xid, arid] of pending) {\n const name = getName(xid);\n requests.push([xid, arid, name]);\n }\n return requests;\n}\n\n/**\n * Simple progress output for non-interactive terminals.\n */\nfunction logProgress(\n direction: Direction,\n name: string,\n status: \"success\" | \"error\" | \"timeout\",\n message?: string,\n): void {\n const emoji = directionEmoji(direction);\n switch (status) {\n case \"success\":\n console.error(`${emoji} ✅ ${name}`);\n break;\n case \"error\":\n console.error(`${emoji} ❌ ${name}: ${message ?? \"Error\"}`);\n break;\n case \"timeout\":\n console.error(`${emoji} ❌ ${name}: Timeout`);\n break;\n }\n}\n\n/**\n * Fetch messages from multiple ARIDs in parallel.\n *\n * Port of `parallel_fetch()` from cmd/parallel.rs.\n */\nexport async function parallelFetch<T>(\n client: StorageClient,\n requests: [XID, ARID, string][],\n validate: (envelope: Envelope, xid: XID) => T | { rejected: string },\n config: ParallelFetchConfig,\n): Promise<CollectionResult<T>> {\n const result = new CollectionResult<T>();\n const timeoutSeconds = config.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS;\n\n if (config.verbose === true) {\n console.error(`Waiting for ${requests.length} responses...`);\n }\n\n const promises = requests.map(async ([xid, arid, name]) => {\n try {\n const envelope = await client.get(arid, timeoutSeconds);\n\n if (!envelope) {\n result.timeouts.push(xid);\n if (config.verbose === true) {\n logProgress(Direction.Get, name, \"timeout\");\n }\n return;\n }\n\n const parsed = validate(envelope, xid);\n\n if (parsed !== null && typeof parsed === \"object\" && \"rejected\" in parsed) {\n result.rejections.push([xid, parsed.rejected]);\n if (config.verbose === true) {\n logProgress(Direction.Get, name, \"error\", parsed.rejected);\n }\n } else {\n result.successes.push([xid, parsed]);\n if (config.verbose === true) {\n logProgress(Direction.Get, name, \"success\");\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (errorMessage.includes(\"Timeout\") || errorMessage.includes(\"timeout\")) {\n result.timeouts.push(xid);\n if (config.verbose === true) {\n logProgress(Direction.Get, name, \"timeout\");\n }\n } else {\n result.errors.push([xid, `${name}: ${errorMessage}`]);\n if (config.verbose === true) {\n logProgress(Direction.Get, name, \"error\", errorMessage);\n }\n }\n }\n });\n\n await Promise.all(promises);\n\n if (config.verbose === true) {\n console.error(`Collected ${result.successes.length} responses`);\n if (result.rejections.length > 0) {\n console.error(` ${result.rejections.length} rejections`);\n }\n if (result.errors.length > 0) {\n console.error(` ${result.errors.length} errors`);\n }\n if (result.timeouts.length > 0) {\n console.error(` ${result.timeouts.length} timeouts`);\n }\n }\n\n return result;\n}\n\n/**\n * Send messages to multiple ARIDs in parallel.\n *\n * Port of `parallel_send()` from cmd/parallel.rs.\n */\nexport async function parallelSend(\n client: StorageClient,\n messages: [XID, ARID, Envelope, string][],\n verbose?: boolean,\n): Promise<[XID, Error | null][]> {\n const results: [XID, Error | null][] = [];\n\n if (verbose === true) {\n console.error(`Sending to ${messages.length} participants...`);\n }\n\n const promises = messages.map(async ([xid, arid, envelope, name]) => {\n try {\n await client.put(arid, envelope);\n results.push([xid, null]);\n if (verbose === true) {\n logProgress(Direction.Put, name, \"success\");\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n results.push([xid, err]);\n if (verbose === true) {\n logProgress(Direction.Put, name, \"error\", err.message);\n }\n }\n });\n\n await Promise.all(promises);\n\n if (verbose === true) {\n const successes = results.filter(([_, err]) => err === null).length;\n const failures = results.length - successes;\n console.error(`Sent ${successes} messages`);\n if (failures > 0) {\n console.error(` ${failures} failed`);\n }\n }\n\n return results;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require("./chunk-CZWwpsFl.cjs");
|
|
2
|
+
let _bcts_envelope = require("@bcts/envelope");
|
|
3
|
+
let _bcts_xid = require("@bcts/xid");
|
|
4
|
+
let _bcts_uniform_resources = require("@bcts/uniform-resources");
|
|
5
|
+
//#region src/dkg/proposed-participant.ts
|
|
6
|
+
/**
|
|
7
|
+
* A proposed participant in a DKG session.
|
|
8
|
+
*
|
|
9
|
+
* Port of `struct DkgProposedParticipant` from proposed_participant.rs lines 8-13.
|
|
10
|
+
*/
|
|
11
|
+
var DkgProposedParticipant = class DkgProposedParticipant {
|
|
12
|
+
_urString;
|
|
13
|
+
_envelope;
|
|
14
|
+
_document;
|
|
15
|
+
_responseArid;
|
|
16
|
+
constructor(urString, envelope, document, responseArid) {
|
|
17
|
+
this._urString = urString;
|
|
18
|
+
this._envelope = envelope;
|
|
19
|
+
this._document = document;
|
|
20
|
+
this._responseArid = responseArid;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new DkgProposedParticipant from a UR string and response ARID.
|
|
24
|
+
*
|
|
25
|
+
* Port of `DkgProposedParticipant::new()` from proposed_participant.rs lines 22-26.
|
|
26
|
+
*/
|
|
27
|
+
static create(urString, responseArid) {
|
|
28
|
+
const [envelope, document] = parseXidEnvelope(urString);
|
|
29
|
+
return new DkgProposedParticipant(urString, envelope, document, responseArid);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the XID of this participant.
|
|
33
|
+
*
|
|
34
|
+
* Port of `DkgProposedParticipant::xid()` from proposed_participant.rs line 28.
|
|
35
|
+
*/
|
|
36
|
+
xid() {
|
|
37
|
+
return this._document.xid();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the XID document of this participant.
|
|
41
|
+
*
|
|
42
|
+
* Port of `DkgProposedParticipant::xid_document()` from proposed_participant.rs line 30.
|
|
43
|
+
*/
|
|
44
|
+
xidDocument() {
|
|
45
|
+
return this._document;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get the UR string of the XID document.
|
|
49
|
+
*
|
|
50
|
+
* Port of `DkgProposedParticipant::xid_document_ur()` from proposed_participant.rs line 32.
|
|
51
|
+
*/
|
|
52
|
+
xidDocumentUr() {
|
|
53
|
+
return this._urString;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the envelope containing the XID document.
|
|
57
|
+
*
|
|
58
|
+
* Port of `DkgProposedParticipant::xid_document_envelope()` from proposed_participant.rs line 34.
|
|
59
|
+
*/
|
|
60
|
+
xidDocumentEnvelope() {
|
|
61
|
+
return this._envelope;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the response ARID for this participant.
|
|
65
|
+
*
|
|
66
|
+
* Port of `DkgProposedParticipant::response_arid()` from proposed_participant.rs line 36.
|
|
67
|
+
*/
|
|
68
|
+
responseArid() {
|
|
69
|
+
return this._responseArid;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Compare participants by XID for sorting.
|
|
73
|
+
*
|
|
74
|
+
* Mirrors Rust `PartialOrd::partial_cmp` which uses
|
|
75
|
+
* `self.xid().cmp(&other.xid())` — i.e. the underlying 32-byte XID
|
|
76
|
+
* data is compared lexicographically (`Vec<u8>` ordering). The
|
|
77
|
+
* earlier port used `xid.toString().localeCompare(...)`, which (a)
|
|
78
|
+
* compares the UR-encoded base32-ish string, not the bytes, and (b)
|
|
79
|
+
* is locale-aware. Sorting on UR strings differs from the byte
|
|
80
|
+
* order whenever the underlying bytes contain values ≥ 0x80, so
|
|
81
|
+
* Rust and TS would assign different FROST identifiers to the same
|
|
82
|
+
* participant set — producing different secret shares.
|
|
83
|
+
*/
|
|
84
|
+
compareTo(other) {
|
|
85
|
+
return compareXidBytes(this.xid().toData(), other.xid().toData());
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Lexicographic byte compare matching Rust's `Vec<u8>::cmp` /
|
|
90
|
+
* `XID::cmp`. Exported so the cmd-tree call sites (round1 / finalize)
|
|
91
|
+
* can use the same comparator when they sort deduplicated XID lists.
|
|
92
|
+
*
|
|
93
|
+
* `XID` is exactly 32 bytes so this only ever compares two equal-length
|
|
94
|
+
* inputs; the length-tiebreak branch mirrors the generic `Ord` impl on
|
|
95
|
+
* `Vec<u8>` and is included for correctness if ever applied to other
|
|
96
|
+
* byte sequences.
|
|
97
|
+
*
|
|
98
|
+
* @internal
|
|
99
|
+
*/
|
|
100
|
+
function compareXidBytes(a, b) {
|
|
101
|
+
const minLen = Math.min(a.length, b.length);
|
|
102
|
+
for (let i = 0; i < minLen; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
|
103
|
+
if (a.length !== b.length) return a.length < b.length ? -1 : 1;
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse a XID envelope from a UR string.
|
|
108
|
+
*
|
|
109
|
+
* Port of `parse_xid_envelope()` from proposed_participant.rs lines 39-60.
|
|
110
|
+
*/
|
|
111
|
+
function parseXidEnvelope(input) {
|
|
112
|
+
const trimmed = input.trim();
|
|
113
|
+
if (trimmed.length === 0) throw new Error("XID document is required");
|
|
114
|
+
const ur = _bcts_uniform_resources.UR.fromURString(trimmed);
|
|
115
|
+
const urType = ur.urTypeStr();
|
|
116
|
+
if (urType !== "xid" && urType !== "envelope") throw new Error(`Expected a ur:xid document, found ur:${urType}`);
|
|
117
|
+
const envelopeCbor = ur.cbor();
|
|
118
|
+
let envelope;
|
|
119
|
+
try {
|
|
120
|
+
envelope = _bcts_envelope.Envelope.fromTaggedCbor(envelopeCbor);
|
|
121
|
+
} catch {
|
|
122
|
+
envelope = _bcts_envelope.Envelope.fromUntaggedCbor(envelopeCbor);
|
|
123
|
+
}
|
|
124
|
+
const document = _bcts_xid.XIDDocument.fromEnvelope(envelope, void 0, _bcts_xid.XIDVerifySignature.Inception);
|
|
125
|
+
return [envelope, document];
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
Object.defineProperty(exports, "DkgProposedParticipant", {
|
|
129
|
+
enumerable: true,
|
|
130
|
+
get: function() {
|
|
131
|
+
return DkgProposedParticipant;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
Object.defineProperty(exports, "compareXidBytes", {
|
|
135
|
+
enumerable: true,
|
|
136
|
+
get: function() {
|
|
137
|
+
return compareXidBytes;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=proposed-participant-Dm1Eq6mX.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposed-participant-Dm1Eq6mX.cjs","names":["UR","Envelope","XIDDocument","XIDVerifySignature"],"sources":["../src/dkg/proposed-participant.ts"],"sourcesContent":["/**\n * Copyright © 2023-2026 Blockchain Commons, LLC\n * Copyright © 2025-2026 Parity Technologies\n *\n *\n * DKG Proposed Participant.\n *\n * Port of dkg/proposed_participant.rs from frost-hubert-rust.\n *\n * @module\n */\n\nimport { type ARID, type XID } from \"@bcts/components\";\nimport { Envelope } from \"@bcts/envelope\";\nimport { UR } from \"@bcts/uniform-resources\";\nimport { XIDDocument, XIDVerifySignature } from \"@bcts/xid\";\n\n/**\n * A proposed participant in a DKG session.\n *\n * Port of `struct DkgProposedParticipant` from proposed_participant.rs lines 8-13.\n */\nexport class DkgProposedParticipant {\n private readonly _urString: string;\n private readonly _envelope: Envelope;\n private readonly _document: XIDDocument;\n private readonly _responseArid: ARID;\n\n private constructor(\n urString: string,\n envelope: Envelope,\n document: XIDDocument,\n responseArid: ARID,\n ) {\n this._urString = urString;\n this._envelope = envelope;\n this._document = document;\n this._responseArid = responseArid;\n }\n\n /**\n * Create a new DkgProposedParticipant from a UR string and response ARID.\n *\n * Port of `DkgProposedParticipant::new()` from proposed_participant.rs lines 22-26.\n */\n static create(urString: string, responseArid: ARID): DkgProposedParticipant {\n const [envelope, document] = parseXidEnvelope(urString);\n return new DkgProposedParticipant(urString, envelope, document, responseArid);\n }\n\n /**\n * Get the XID of this participant.\n *\n * Port of `DkgProposedParticipant::xid()` from proposed_participant.rs line 28.\n */\n xid(): XID {\n return this._document.xid();\n }\n\n /**\n * Get the XID document of this participant.\n *\n * Port of `DkgProposedParticipant::xid_document()` from proposed_participant.rs line 30.\n */\n xidDocument(): XIDDocument {\n return this._document;\n }\n\n /**\n * Get the UR string of the XID document.\n *\n * Port of `DkgProposedParticipant::xid_document_ur()` from proposed_participant.rs line 32.\n */\n xidDocumentUr(): string {\n return this._urString;\n }\n\n /**\n * Get the envelope containing the XID document.\n *\n * Port of `DkgProposedParticipant::xid_document_envelope()` from proposed_participant.rs line 34.\n */\n xidDocumentEnvelope(): Envelope {\n return this._envelope;\n }\n\n /**\n * Get the response ARID for this participant.\n *\n * Port of `DkgProposedParticipant::response_arid()` from proposed_participant.rs line 36.\n */\n responseArid(): ARID {\n return this._responseArid;\n }\n\n /**\n * Compare participants by XID for sorting.\n *\n * Mirrors Rust `PartialOrd::partial_cmp` which uses\n * `self.xid().cmp(&other.xid())` — i.e. the underlying 32-byte XID\n * data is compared lexicographically (`Vec<u8>` ordering). The\n * earlier port used `xid.toString().localeCompare(...)`, which (a)\n * compares the UR-encoded base32-ish string, not the bytes, and (b)\n * is locale-aware. Sorting on UR strings differs from the byte\n * order whenever the underlying bytes contain values ≥ 0x80, so\n * Rust and TS would assign different FROST identifiers to the same\n * participant set — producing different secret shares.\n */\n compareTo(other: DkgProposedParticipant): number {\n return compareXidBytes(this.xid().toData(), other.xid().toData());\n }\n}\n\n/**\n * Lexicographic byte compare matching Rust's `Vec<u8>::cmp` /\n * `XID::cmp`. Exported so the cmd-tree call sites (round1 / finalize)\n * can use the same comparator when they sort deduplicated XID lists.\n *\n * `XID` is exactly 32 bytes so this only ever compares two equal-length\n * inputs; the length-tiebreak branch mirrors the generic `Ord` impl on\n * `Vec<u8>` and is included for correctness if ever applied to other\n * byte sequences.\n *\n * @internal\n */\nexport function compareXidBytes(a: Uint8Array, b: Uint8Array): number {\n const minLen = Math.min(a.length, b.length);\n for (let i = 0; i < minLen; i++) {\n if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;\n }\n if (a.length !== b.length) return a.length < b.length ? -1 : 1;\n return 0;\n}\n\n/**\n * Parse a XID envelope from a UR string.\n *\n * Port of `parse_xid_envelope()` from proposed_participant.rs lines 39-60.\n */\nfunction parseXidEnvelope(input: string): [Envelope, XIDDocument] {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw new Error(\"XID document is required\");\n }\n\n const ur = UR.fromURString(trimmed);\n const urType = ur.urTypeStr();\n if (urType !== \"xid\" && urType !== \"envelope\") {\n throw new Error(`Expected a ur:xid document, found ur:${urType}`);\n }\n\n const envelopeCbor = ur.cbor();\n // Try tagged CBOR first, then untagged\n let envelope: Envelope;\n try {\n envelope = Envelope.fromTaggedCbor(envelopeCbor);\n } catch {\n envelope = Envelope.fromUntaggedCbor(envelopeCbor);\n }\n\n const document = XIDDocument.fromEnvelope(envelope, undefined, XIDVerifySignature.Inception);\n\n return [envelope, document];\n}\n"],"mappings":";;;;;;;;;;AAsBA,IAAa,yBAAb,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CAEA,YACE,UACA,UACA,UACA,cACA;AACA,OAAK,YAAY;AACjB,OAAK,YAAY;AACjB,OAAK,YAAY;AACjB,OAAK,gBAAgB;;;;;;;CAQvB,OAAO,OAAO,UAAkB,cAA4C;EAC1E,MAAM,CAAC,UAAU,YAAY,iBAAiB,SAAS;AACvD,SAAO,IAAI,uBAAuB,UAAU,UAAU,UAAU,aAAa;;;;;;;CAQ/E,MAAW;AACT,SAAO,KAAK,UAAU,KAAK;;;;;;;CAQ7B,cAA2B;AACzB,SAAO,KAAK;;;;;;;CAQd,gBAAwB;AACtB,SAAO,KAAK;;;;;;;CAQd,sBAAgC;AAC9B,SAAO,KAAK;;;;;;;CAQd,eAAqB;AACnB,SAAO,KAAK;;;;;;;;;;;;;;;CAgBd,UAAU,OAAuC;AAC/C,SAAO,gBAAgB,KAAK,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;AAgBrE,SAAgB,gBAAgB,GAAe,GAAuB;CACpE,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAC1B,KAAI,EAAE,OAAO,EAAE,GAAI,QAAO,EAAE,KAAK,EAAE,KAAK,KAAK;AAE/C,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO,EAAE,SAAS,EAAE,SAAS,KAAK;AAC7D,QAAO;;;;;;;AAQT,SAAS,iBAAiB,OAAwC;CAChE,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,2BAA2B;CAG7C,MAAM,KAAKA,wBAAAA,GAAG,aAAa,QAAQ;CACnC,MAAM,SAAS,GAAG,WAAW;AAC7B,KAAI,WAAW,SAAS,WAAW,WACjC,OAAM,IAAI,MAAM,wCAAwC,SAAS;CAGnE,MAAM,eAAe,GAAG,MAAM;CAE9B,IAAI;AACJ,KAAI;AACF,aAAWC,eAAAA,SAAS,eAAe,aAAa;SAC1C;AACN,aAAWA,eAAAA,SAAS,iBAAiB,aAAa;;CAGpD,MAAM,WAAWC,UAAAA,YAAY,aAAa,UAAU,KAAA,GAAWC,UAAAA,mBAAmB,UAAU;AAE5F,QAAO,CAAC,UAAU,SAAS"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Envelope } from "@bcts/envelope";
|
|
2
|
+
import { XIDDocument, XIDVerifySignature } from "@bcts/xid";
|
|
3
|
+
import { UR } from "@bcts/uniform-resources";
|
|
4
|
+
//#region src/dkg/proposed-participant.ts
|
|
5
|
+
/**
|
|
6
|
+
* A proposed participant in a DKG session.
|
|
7
|
+
*
|
|
8
|
+
* Port of `struct DkgProposedParticipant` from proposed_participant.rs lines 8-13.
|
|
9
|
+
*/
|
|
10
|
+
var DkgProposedParticipant = class DkgProposedParticipant {
|
|
11
|
+
_urString;
|
|
12
|
+
_envelope;
|
|
13
|
+
_document;
|
|
14
|
+
_responseArid;
|
|
15
|
+
constructor(urString, envelope, document, responseArid) {
|
|
16
|
+
this._urString = urString;
|
|
17
|
+
this._envelope = envelope;
|
|
18
|
+
this._document = document;
|
|
19
|
+
this._responseArid = responseArid;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a new DkgProposedParticipant from a UR string and response ARID.
|
|
23
|
+
*
|
|
24
|
+
* Port of `DkgProposedParticipant::new()` from proposed_participant.rs lines 22-26.
|
|
25
|
+
*/
|
|
26
|
+
static create(urString, responseArid) {
|
|
27
|
+
const [envelope, document] = parseXidEnvelope(urString);
|
|
28
|
+
return new DkgProposedParticipant(urString, envelope, document, responseArid);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the XID of this participant.
|
|
32
|
+
*
|
|
33
|
+
* Port of `DkgProposedParticipant::xid()` from proposed_participant.rs line 28.
|
|
34
|
+
*/
|
|
35
|
+
xid() {
|
|
36
|
+
return this._document.xid();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the XID document of this participant.
|
|
40
|
+
*
|
|
41
|
+
* Port of `DkgProposedParticipant::xid_document()` from proposed_participant.rs line 30.
|
|
42
|
+
*/
|
|
43
|
+
xidDocument() {
|
|
44
|
+
return this._document;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the UR string of the XID document.
|
|
48
|
+
*
|
|
49
|
+
* Port of `DkgProposedParticipant::xid_document_ur()` from proposed_participant.rs line 32.
|
|
50
|
+
*/
|
|
51
|
+
xidDocumentUr() {
|
|
52
|
+
return this._urString;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the envelope containing the XID document.
|
|
56
|
+
*
|
|
57
|
+
* Port of `DkgProposedParticipant::xid_document_envelope()` from proposed_participant.rs line 34.
|
|
58
|
+
*/
|
|
59
|
+
xidDocumentEnvelope() {
|
|
60
|
+
return this._envelope;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get the response ARID for this participant.
|
|
64
|
+
*
|
|
65
|
+
* Port of `DkgProposedParticipant::response_arid()` from proposed_participant.rs line 36.
|
|
66
|
+
*/
|
|
67
|
+
responseArid() {
|
|
68
|
+
return this._responseArid;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compare participants by XID for sorting.
|
|
72
|
+
*
|
|
73
|
+
* Mirrors Rust `PartialOrd::partial_cmp` which uses
|
|
74
|
+
* `self.xid().cmp(&other.xid())` — i.e. the underlying 32-byte XID
|
|
75
|
+
* data is compared lexicographically (`Vec<u8>` ordering). The
|
|
76
|
+
* earlier port used `xid.toString().localeCompare(...)`, which (a)
|
|
77
|
+
* compares the UR-encoded base32-ish string, not the bytes, and (b)
|
|
78
|
+
* is locale-aware. Sorting on UR strings differs from the byte
|
|
79
|
+
* order whenever the underlying bytes contain values ≥ 0x80, so
|
|
80
|
+
* Rust and TS would assign different FROST identifiers to the same
|
|
81
|
+
* participant set — producing different secret shares.
|
|
82
|
+
*/
|
|
83
|
+
compareTo(other) {
|
|
84
|
+
return compareXidBytes(this.xid().toData(), other.xid().toData());
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Lexicographic byte compare matching Rust's `Vec<u8>::cmp` /
|
|
89
|
+
* `XID::cmp`. Exported so the cmd-tree call sites (round1 / finalize)
|
|
90
|
+
* can use the same comparator when they sort deduplicated XID lists.
|
|
91
|
+
*
|
|
92
|
+
* `XID` is exactly 32 bytes so this only ever compares two equal-length
|
|
93
|
+
* inputs; the length-tiebreak branch mirrors the generic `Ord` impl on
|
|
94
|
+
* `Vec<u8>` and is included for correctness if ever applied to other
|
|
95
|
+
* byte sequences.
|
|
96
|
+
*
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
function compareXidBytes(a, b) {
|
|
100
|
+
const minLen = Math.min(a.length, b.length);
|
|
101
|
+
for (let i = 0; i < minLen; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
|
102
|
+
if (a.length !== b.length) return a.length < b.length ? -1 : 1;
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse a XID envelope from a UR string.
|
|
107
|
+
*
|
|
108
|
+
* Port of `parse_xid_envelope()` from proposed_participant.rs lines 39-60.
|
|
109
|
+
*/
|
|
110
|
+
function parseXidEnvelope(input) {
|
|
111
|
+
const trimmed = input.trim();
|
|
112
|
+
if (trimmed.length === 0) throw new Error("XID document is required");
|
|
113
|
+
const ur = UR.fromURString(trimmed);
|
|
114
|
+
const urType = ur.urTypeStr();
|
|
115
|
+
if (urType !== "xid" && urType !== "envelope") throw new Error(`Expected a ur:xid document, found ur:${urType}`);
|
|
116
|
+
const envelopeCbor = ur.cbor();
|
|
117
|
+
let envelope;
|
|
118
|
+
try {
|
|
119
|
+
envelope = Envelope.fromTaggedCbor(envelopeCbor);
|
|
120
|
+
} catch {
|
|
121
|
+
envelope = Envelope.fromUntaggedCbor(envelopeCbor);
|
|
122
|
+
}
|
|
123
|
+
const document = XIDDocument.fromEnvelope(envelope, void 0, XIDVerifySignature.Inception);
|
|
124
|
+
return [envelope, document];
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { compareXidBytes as n, DkgProposedParticipant as t };
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=proposed-participant-cWM7iUrO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposed-participant-cWM7iUrO.mjs","names":[],"sources":["../src/dkg/proposed-participant.ts"],"sourcesContent":["/**\n * Copyright © 2023-2026 Blockchain Commons, LLC\n * Copyright © 2025-2026 Parity Technologies\n *\n *\n * DKG Proposed Participant.\n *\n * Port of dkg/proposed_participant.rs from frost-hubert-rust.\n *\n * @module\n */\n\nimport { type ARID, type XID } from \"@bcts/components\";\nimport { Envelope } from \"@bcts/envelope\";\nimport { UR } from \"@bcts/uniform-resources\";\nimport { XIDDocument, XIDVerifySignature } from \"@bcts/xid\";\n\n/**\n * A proposed participant in a DKG session.\n *\n * Port of `struct DkgProposedParticipant` from proposed_participant.rs lines 8-13.\n */\nexport class DkgProposedParticipant {\n private readonly _urString: string;\n private readonly _envelope: Envelope;\n private readonly _document: XIDDocument;\n private readonly _responseArid: ARID;\n\n private constructor(\n urString: string,\n envelope: Envelope,\n document: XIDDocument,\n responseArid: ARID,\n ) {\n this._urString = urString;\n this._envelope = envelope;\n this._document = document;\n this._responseArid = responseArid;\n }\n\n /**\n * Create a new DkgProposedParticipant from a UR string and response ARID.\n *\n * Port of `DkgProposedParticipant::new()` from proposed_participant.rs lines 22-26.\n */\n static create(urString: string, responseArid: ARID): DkgProposedParticipant {\n const [envelope, document] = parseXidEnvelope(urString);\n return new DkgProposedParticipant(urString, envelope, document, responseArid);\n }\n\n /**\n * Get the XID of this participant.\n *\n * Port of `DkgProposedParticipant::xid()` from proposed_participant.rs line 28.\n */\n xid(): XID {\n return this._document.xid();\n }\n\n /**\n * Get the XID document of this participant.\n *\n * Port of `DkgProposedParticipant::xid_document()` from proposed_participant.rs line 30.\n */\n xidDocument(): XIDDocument {\n return this._document;\n }\n\n /**\n * Get the UR string of the XID document.\n *\n * Port of `DkgProposedParticipant::xid_document_ur()` from proposed_participant.rs line 32.\n */\n xidDocumentUr(): string {\n return this._urString;\n }\n\n /**\n * Get the envelope containing the XID document.\n *\n * Port of `DkgProposedParticipant::xid_document_envelope()` from proposed_participant.rs line 34.\n */\n xidDocumentEnvelope(): Envelope {\n return this._envelope;\n }\n\n /**\n * Get the response ARID for this participant.\n *\n * Port of `DkgProposedParticipant::response_arid()` from proposed_participant.rs line 36.\n */\n responseArid(): ARID {\n return this._responseArid;\n }\n\n /**\n * Compare participants by XID for sorting.\n *\n * Mirrors Rust `PartialOrd::partial_cmp` which uses\n * `self.xid().cmp(&other.xid())` — i.e. the underlying 32-byte XID\n * data is compared lexicographically (`Vec<u8>` ordering). The\n * earlier port used `xid.toString().localeCompare(...)`, which (a)\n * compares the UR-encoded base32-ish string, not the bytes, and (b)\n * is locale-aware. Sorting on UR strings differs from the byte\n * order whenever the underlying bytes contain values ≥ 0x80, so\n * Rust and TS would assign different FROST identifiers to the same\n * participant set — producing different secret shares.\n */\n compareTo(other: DkgProposedParticipant): number {\n return compareXidBytes(this.xid().toData(), other.xid().toData());\n }\n}\n\n/**\n * Lexicographic byte compare matching Rust's `Vec<u8>::cmp` /\n * `XID::cmp`. Exported so the cmd-tree call sites (round1 / finalize)\n * can use the same comparator when they sort deduplicated XID lists.\n *\n * `XID` is exactly 32 bytes so this only ever compares two equal-length\n * inputs; the length-tiebreak branch mirrors the generic `Ord` impl on\n * `Vec<u8>` and is included for correctness if ever applied to other\n * byte sequences.\n *\n * @internal\n */\nexport function compareXidBytes(a: Uint8Array, b: Uint8Array): number {\n const minLen = Math.min(a.length, b.length);\n for (let i = 0; i < minLen; i++) {\n if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;\n }\n if (a.length !== b.length) return a.length < b.length ? -1 : 1;\n return 0;\n}\n\n/**\n * Parse a XID envelope from a UR string.\n *\n * Port of `parse_xid_envelope()` from proposed_participant.rs lines 39-60.\n */\nfunction parseXidEnvelope(input: string): [Envelope, XIDDocument] {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw new Error(\"XID document is required\");\n }\n\n const ur = UR.fromURString(trimmed);\n const urType = ur.urTypeStr();\n if (urType !== \"xid\" && urType !== \"envelope\") {\n throw new Error(`Expected a ur:xid document, found ur:${urType}`);\n }\n\n const envelopeCbor = ur.cbor();\n // Try tagged CBOR first, then untagged\n let envelope: Envelope;\n try {\n envelope = Envelope.fromTaggedCbor(envelopeCbor);\n } catch {\n envelope = Envelope.fromUntaggedCbor(envelopeCbor);\n }\n\n const document = XIDDocument.fromEnvelope(envelope, undefined, XIDVerifySignature.Inception);\n\n return [envelope, document];\n}\n"],"mappings":";;;;;;;;;AAsBA,IAAa,yBAAb,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;CAEA,YACE,UACA,UACA,UACA,cACA;AACA,OAAK,YAAY;AACjB,OAAK,YAAY;AACjB,OAAK,YAAY;AACjB,OAAK,gBAAgB;;;;;;;CAQvB,OAAO,OAAO,UAAkB,cAA4C;EAC1E,MAAM,CAAC,UAAU,YAAY,iBAAiB,SAAS;AACvD,SAAO,IAAI,uBAAuB,UAAU,UAAU,UAAU,aAAa;;;;;;;CAQ/E,MAAW;AACT,SAAO,KAAK,UAAU,KAAK;;;;;;;CAQ7B,cAA2B;AACzB,SAAO,KAAK;;;;;;;CAQd,gBAAwB;AACtB,SAAO,KAAK;;;;;;;CAQd,sBAAgC;AAC9B,SAAO,KAAK;;;;;;;CAQd,eAAqB;AACnB,SAAO,KAAK;;;;;;;;;;;;;;;CAgBd,UAAU,OAAuC;AAC/C,SAAO,gBAAgB,KAAK,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;AAgBrE,SAAgB,gBAAgB,GAAe,GAAuB;CACpE,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAC1B,KAAI,EAAE,OAAO,EAAE,GAAI,QAAO,EAAE,KAAK,EAAE,KAAK,KAAK;AAE/C,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO,EAAE,SAAS,EAAE,SAAS,KAAK;AAC7D,QAAO;;;;;;;AAQT,SAAS,iBAAiB,OAAwC;CAChE,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,2BAA2B;CAG7C,MAAM,KAAK,GAAG,aAAa,QAAQ;CACnC,MAAM,SAAS,GAAG,WAAW;AAC7B,KAAI,WAAW,SAAS,WAAW,WACjC,OAAM,IAAI,MAAM,wCAAwC,SAAS;CAGnE,MAAM,eAAe,GAAG,MAAM;CAE9B,IAAI;AACJ,KAAI;AACF,aAAW,SAAS,eAAe,aAAa;SAC1C;AACN,aAAW,SAAS,iBAAiB,aAAa;;CAGpD,MAAM,WAAW,YAAY,aAAa,UAAU,KAAA,GAAW,mBAAmB,UAAU;AAE5F,QAAO,CAAC,UAAU,SAAS"}
|