@umbra-privacy/ceremony 0.2.5 → 0.2.6
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/index.js +93 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { render } from "ink";
|
|
5
5
|
|
|
6
6
|
// src/components/App.tsx
|
|
7
|
-
import { useEffect as
|
|
7
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
8
8
|
import { Box as Box7, Text as Text7, useApp, useInput as useInput2 } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/cleanup.ts
|
|
@@ -315,22 +315,61 @@ function Header({ ceremony, subtitle }) {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// src/components/QueueView.tsx
|
|
318
|
-
import { useEffect, useRef, useState } from "react";
|
|
318
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
319
319
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
320
320
|
import Spinner from "ink-spinner";
|
|
321
|
-
|
|
321
|
+
|
|
322
|
+
// src/hooks/useCyclingMessage.ts
|
|
323
|
+
import { useEffect, useState } from "react";
|
|
324
|
+
function useCyclingMessage(messages, intervalMs = 2500, active = true) {
|
|
325
|
+
const [idx, setIdx] = useState(0);
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
if (!active || messages.length <= 1) return;
|
|
328
|
+
const t = setInterval(() => setIdx((i) => (i + 1) % messages.length), intervalMs);
|
|
329
|
+
return () => clearInterval(t);
|
|
330
|
+
}, [active, intervalMs, messages.length]);
|
|
331
|
+
return messages[idx] ?? messages[0] ?? "";
|
|
332
|
+
}
|
|
333
|
+
var COMPUTING_MESSAGES = [
|
|
334
|
+
"summoning fresh entropy",
|
|
335
|
+
"shuffling response bytes",
|
|
336
|
+
"tickling bn128 pairings",
|
|
337
|
+
"applying tau locally",
|
|
338
|
+
"folding contribution proof",
|
|
339
|
+
"blinding the trapdoor",
|
|
340
|
+
"sealing the bellman response"
|
|
341
|
+
];
|
|
342
|
+
var VERIFYING_MESSAGES = [
|
|
343
|
+
"worker pulling your response from S3",
|
|
344
|
+
"importing bellman contribution into a new zkey",
|
|
345
|
+
"checking the contribution's pairing proof",
|
|
346
|
+
"writing the next zkey",
|
|
347
|
+
"uploading the new zkey",
|
|
348
|
+
"anchoring contribution hash in the audit chain",
|
|
349
|
+
"almost there \u2014 finalising your receipt"
|
|
350
|
+
];
|
|
351
|
+
var EXPORTING_MESSAGES = [
|
|
352
|
+
"preparing your challenge file",
|
|
353
|
+
"extracting bellman params from the current zkey",
|
|
354
|
+
"wrapping the zkey for handoff",
|
|
355
|
+
"stamping a sha256 over the challenge bundle",
|
|
356
|
+
"presigning your download URL"
|
|
357
|
+
];
|
|
358
|
+
|
|
359
|
+
// src/components/QueueView.tsx
|
|
360
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
322
361
|
var POLL_FAST_MS = 5e3;
|
|
323
362
|
var POLL_SLOW_MS = 15e3;
|
|
324
363
|
function QueueView({ ceremonyId: ceremonyId2, trackId, token, onReady, onError }) {
|
|
325
|
-
const [status, setStatus] =
|
|
326
|
-
const [pollErr, setPollErr] =
|
|
327
|
-
const [tick, setTick] =
|
|
364
|
+
const [status, setStatus] = useState2(null);
|
|
365
|
+
const [pollErr, setPollErr] = useState2(null);
|
|
366
|
+
const [tick, setTick] = useState2(0);
|
|
328
367
|
const timeoutRef = useRef(null);
|
|
329
|
-
|
|
368
|
+
useEffect2(() => {
|
|
330
369
|
const id = setInterval(() => setTick((t) => (t + 1) % 4), 500);
|
|
331
370
|
return () => clearInterval(id);
|
|
332
371
|
}, []);
|
|
333
|
-
|
|
372
|
+
useEffect2(() => {
|
|
334
373
|
let cancelled = false;
|
|
335
374
|
async function poll() {
|
|
336
375
|
try {
|
|
@@ -395,7 +434,7 @@ function QueueView({ ceremonyId: ceremonyId2, trackId, token, onReady, onError }
|
|
|
395
434
|
] })
|
|
396
435
|
] })
|
|
397
436
|
] }),
|
|
398
|
-
status.status === "exporting" || status.status === "your_turn" || status.status === "ready_to_download" ? /* @__PURE__ */ jsx2(
|
|
437
|
+
status.status === "exporting" || status.status === "your_turn" || status.status === "ready_to_download" ? /* @__PURE__ */ jsx2(ExportingMessage, { status: status.status }) : status.active_since ? /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
399
438
|
"Another contributor is active",
|
|
400
439
|
expiresAt ? ` \xB7 slot expires at ${expiresAt}` : ""
|
|
401
440
|
] }) }) : status.queue_position > 1 ? (
|
|
@@ -419,9 +458,21 @@ function QueueView({ ceremonyId: ceremonyId2, trackId, token, onReady, onError }
|
|
|
419
458
|
] })
|
|
420
459
|
] });
|
|
421
460
|
}
|
|
461
|
+
function ExportingMessage({ status }) {
|
|
462
|
+
const exportingMsg = useCyclingMessage(EXPORTING_MESSAGES, 2500, status === "exporting");
|
|
463
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: status === "exporting" ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
464
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "green", children: [
|
|
465
|
+
/* @__PURE__ */ jsx2(Spinner, { type: "dots" }),
|
|
466
|
+
" ",
|
|
467
|
+
exportingMsg,
|
|
468
|
+
"\u2026"
|
|
469
|
+
] }),
|
|
470
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Your slot is active. The worker is preparing the challenge file just for you." })
|
|
471
|
+
] }) : /* @__PURE__ */ jsx2(Text2, { color: "green", children: "Challenge ready \u2014 loading contribution flow\u2026" }) });
|
|
472
|
+
}
|
|
422
473
|
|
|
423
474
|
// src/components/EntropyCollector.tsx
|
|
424
|
-
import { useRef as useRef2, useState as
|
|
475
|
+
import { useRef as useRef2, useState as useState3 } from "react";
|
|
425
476
|
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
426
477
|
|
|
427
478
|
// src/entropy.ts
|
|
@@ -442,8 +493,8 @@ function buildEntropyFromKeystrokes(chars, timingsNs) {
|
|
|
442
493
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
443
494
|
var TARGET = 20;
|
|
444
495
|
function EntropyCollector({ onComplete, onError }) {
|
|
445
|
-
const [count, setCount] =
|
|
446
|
-
const [done, setDone] =
|
|
496
|
+
const [count, setCount] = useState3(0);
|
|
497
|
+
const [done, setDone] = useState3(false);
|
|
447
498
|
const charsRef = useRef2([]);
|
|
448
499
|
const timingsRef = useRef2([]);
|
|
449
500
|
const lastRef = useRef2(process.hrtime.bigint());
|
|
@@ -511,7 +562,7 @@ function EntropyCollector({ onComplete, onError }) {
|
|
|
511
562
|
}
|
|
512
563
|
|
|
513
564
|
// src/components/ContributeFlow.tsx
|
|
514
|
-
import { useEffect as
|
|
565
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
515
566
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
516
567
|
import Spinner2 from "ink-spinner";
|
|
517
568
|
import { tmpdir as tmpdir2 } from "os";
|
|
@@ -550,8 +601,8 @@ var STEP_INDEX = {
|
|
|
550
601
|
};
|
|
551
602
|
function ContributeFlow(props) {
|
|
552
603
|
const { ceremonyId: ceremonyId2, trackId, token, slotStatus, entropy, displayName: displayName2 } = props;
|
|
553
|
-
const [step, setStep] =
|
|
554
|
-
|
|
604
|
+
const [step, setStep] = useState4({ name: "downloading", bytesReceived: 0, total: null });
|
|
605
|
+
useEffect4(() => {
|
|
555
606
|
let cancelled = false;
|
|
556
607
|
const challengePath = join4(tmpdir2(), `ceremony-challenge-${Date.now()}.mpcparams`);
|
|
557
608
|
let responsePath = null;
|
|
@@ -597,8 +648,8 @@ function ContributeFlow(props) {
|
|
|
597
648
|
await api.signalUploaded(ceremonyId2, trackId, slotStatus.contribution_id, token);
|
|
598
649
|
if (cancelled) return;
|
|
599
650
|
setStep({ name: "verifying", attempt: 1 });
|
|
600
|
-
const TOTAL_POLLS =
|
|
601
|
-
const FAST_POLLS =
|
|
651
|
+
const TOTAL_POLLS = 100;
|
|
652
|
+
const FAST_POLLS = 10;
|
|
602
653
|
let receipt = null;
|
|
603
654
|
let lastErr = null;
|
|
604
655
|
for (let i = 0; i < TOTAL_POLLS; i++) {
|
|
@@ -632,6 +683,8 @@ function ContributeFlow(props) {
|
|
|
632
683
|
};
|
|
633
684
|
}, []);
|
|
634
685
|
const currentIdx = STEP_INDEX[step.name] ?? 0;
|
|
686
|
+
const computingMsg = useCyclingMessage(COMPUTING_MESSAGES, 2500, step.name === "computing");
|
|
687
|
+
const verifyingMsg = useCyclingMessage(VERIFYING_MESSAGES, 3e3, step.name === "verifying");
|
|
635
688
|
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", gap: 1, children: STEP_LABELS.map((label, i) => {
|
|
636
689
|
const isDone = i < currentIdx;
|
|
637
690
|
const isActive = i === currentIdx;
|
|
@@ -655,17 +708,25 @@ function ContributeFlow(props) {
|
|
|
655
708
|
] });
|
|
656
709
|
}
|
|
657
710
|
if (isActive && step.name === "verifying") {
|
|
658
|
-
const elapsed = step.attempt <=
|
|
711
|
+
const elapsed = step.attempt <= 10 ? step.attempt * 3 : 10 * 3 + (step.attempt - 10) * 10;
|
|
659
712
|
const mins = Math.floor(elapsed / 60);
|
|
660
713
|
const secs = elapsed % 60;
|
|
661
714
|
const time = mins > 0 ? `${mins}m ${secs.toString().padStart(2, "0")}s` : `${secs}s`;
|
|
662
715
|
detail = /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
663
716
|
" ",
|
|
664
|
-
|
|
717
|
+
verifyingMsg,
|
|
718
|
+
"\u2026 (",
|
|
665
719
|
time,
|
|
666
720
|
" elapsed)"
|
|
667
721
|
] });
|
|
668
722
|
}
|
|
723
|
+
if (isActive && step.name === "computing") {
|
|
724
|
+
detail = /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
725
|
+
" ",
|
|
726
|
+
computingMsg,
|
|
727
|
+
"\u2026"
|
|
728
|
+
] });
|
|
729
|
+
}
|
|
669
730
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
670
731
|
/* @__PURE__ */ jsxs4(Box4, { gap: 2, children: [
|
|
671
732
|
indicator,
|
|
@@ -678,8 +739,7 @@ function ContributeFlow(props) {
|
|
|
678
739
|
children: [
|
|
679
740
|
label.charAt(0).toUpperCase() + label.slice(1),
|
|
680
741
|
" ",
|
|
681
|
-
isActive && label === "computing" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "(entropy stays local)" })
|
|
682
|
-
isActive && label === "uploading" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "(~544 bytes)" })
|
|
742
|
+
isActive && label === "computing" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "(entropy stays local)" })
|
|
683
743
|
]
|
|
684
744
|
}
|
|
685
745
|
)
|
|
@@ -755,19 +815,19 @@ var NAME_MAX_LEN = 100;
|
|
|
755
815
|
var NAME_VALID_RE = /^[\p{L}\p{N} _.\-]*$/u;
|
|
756
816
|
function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName }) {
|
|
757
817
|
const { exit } = useApp();
|
|
758
|
-
const [activeCeremonyId, setActiveCeremonyId] =
|
|
759
|
-
const [displayName2, setDisplayName] =
|
|
760
|
-
const [nameSet, setNameSet] =
|
|
761
|
-
const [screen, setScreen] =
|
|
818
|
+
const [activeCeremonyId, setActiveCeremonyId] = useState5(initialCeremonyId);
|
|
819
|
+
const [displayName2, setDisplayName] = useState5(initialDisplayName ?? "anonymous");
|
|
820
|
+
const [nameSet, setNameSet] = useState5(initialDisplayName !== void 0);
|
|
821
|
+
const [screen, setScreen] = useState5(
|
|
762
822
|
initialDisplayName === void 0 ? { name: "name-input", value: "" } : initialCeremonyId ? { name: "loading" } : { name: "ceremony-picker", ceremonies: [], loading: true }
|
|
763
823
|
);
|
|
764
|
-
const [ceremony, setCeremony] =
|
|
765
|
-
const [session, setSession] =
|
|
766
|
-
const [contributed, setContributed] =
|
|
767
|
-
const [selectedIdx, setSelectedIdx] =
|
|
768
|
-
const [tab, setTab] =
|
|
769
|
-
const [showInfo, setShowInfo] =
|
|
770
|
-
|
|
824
|
+
const [ceremony, setCeremony] = useState5(null);
|
|
825
|
+
const [session, setSession] = useState5(null);
|
|
826
|
+
const [contributed, setContributed] = useState5({});
|
|
827
|
+
const [selectedIdx, setSelectedIdx] = useState5(0);
|
|
828
|
+
const [tab, setTab] = useState5(0);
|
|
829
|
+
const [showInfo, setShowInfo] = useState5(false);
|
|
830
|
+
useEffect5(() => {
|
|
771
831
|
if (!nameSet) return;
|
|
772
832
|
if (!initialCeremonyId) {
|
|
773
833
|
loadCeremonies();
|
|
@@ -890,7 +950,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
|
|
|
890
950
|
setScreen({ name: "ceremony-picker", ceremonies: [], loading: true });
|
|
891
951
|
loadCeremonies();
|
|
892
952
|
}
|
|
893
|
-
|
|
953
|
+
useEffect5(() => {
|
|
894
954
|
if (screen.name === "queue" && session) {
|
|
895
955
|
const { trackId } = screen;
|
|
896
956
|
setQueueCleanup(() => {
|