@cello-protocol/daemon 0.0.3 → 0.0.4

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.
Files changed (153) hide show
  1. package/dist/agent-loader.d.ts +41 -0
  2. package/dist/agent-loader.d.ts.map +1 -0
  3. package/dist/agent-loader.js +94 -0
  4. package/dist/agent-loader.js.map +1 -0
  5. package/dist/bin/cello-daemon.d.ts +13 -0
  6. package/dist/bin/cello-daemon.d.ts.map +1 -0
  7. package/dist/bin/cello-daemon.js +170 -0
  8. package/dist/bin/cello-daemon.js.map +1 -0
  9. package/dist/cello-node-transport-dialer.d.ts +59 -0
  10. package/dist/cello-node-transport-dialer.d.ts.map +1 -0
  11. package/dist/cello-node-transport-dialer.js +108 -0
  12. package/dist/cello-node-transport-dialer.js.map +1 -0
  13. package/dist/challenge-verifier.d.ts +12 -0
  14. package/dist/challenge-verifier.d.ts.map +1 -0
  15. package/dist/challenge-verifier.js +11 -0
  16. package/dist/challenge-verifier.js.map +1 -0
  17. package/dist/connect-or-start.d.ts +25 -0
  18. package/dist/connect-or-start.d.ts.map +1 -0
  19. package/dist/connect-or-start.js +117 -0
  20. package/dist/connect-or-start.js.map +1 -0
  21. package/dist/content-park-client.d.ts +49 -0
  22. package/dist/content-park-client.d.ts.map +1 -0
  23. package/dist/content-park-client.js +196 -0
  24. package/dist/content-park-client.js.map +1 -0
  25. package/dist/daemon.d.ts +65 -0
  26. package/dist/daemon.d.ts.map +1 -0
  27. package/dist/daemon.js +3202 -0
  28. package/dist/daemon.js.map +1 -0
  29. package/dist/directory-bootstrap.d.ts +55 -0
  30. package/dist/directory-bootstrap.d.ts.map +1 -0
  31. package/dist/directory-bootstrap.js +102 -0
  32. package/dist/directory-bootstrap.js.map +1 -0
  33. package/dist/file-manifest-provider.d.ts +18 -0
  34. package/dist/file-manifest-provider.d.ts.map +1 -0
  35. package/dist/file-manifest-provider.js +72 -0
  36. package/dist/file-manifest-provider.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/ipc-client.d.ts +31 -0
  42. package/dist/ipc-client.d.ts.map +1 -0
  43. package/dist/ipc-client.js +112 -0
  44. package/dist/ipc-client.js.map +1 -0
  45. package/dist/ipc-server.d.ts +49 -0
  46. package/dist/ipc-server.d.ts.map +1 -0
  47. package/dist/ipc-server.js +268 -0
  48. package/dist/ipc-server.js.map +1 -0
  49. package/dist/lock-file.d.ts +27 -0
  50. package/dist/lock-file.d.ts.map +1 -0
  51. package/dist/lock-file.js +84 -0
  52. package/dist/lock-file.js.map +1 -0
  53. package/dist/manifest-loader.d.ts +33 -0
  54. package/dist/manifest-loader.d.ts.map +1 -0
  55. package/dist/manifest-loader.js +70 -0
  56. package/dist/manifest-loader.js.map +1 -0
  57. package/dist/manifest-poll-scheduler.d.ts +31 -0
  58. package/dist/manifest-poll-scheduler.d.ts.map +1 -0
  59. package/dist/manifest-poll-scheduler.js +59 -0
  60. package/dist/manifest-poll-scheduler.js.map +1 -0
  61. package/dist/manifest-version-store-file.d.ts +18 -0
  62. package/dist/manifest-version-store-file.d.ts.map +1 -0
  63. package/dist/manifest-version-store-file.js +40 -0
  64. package/dist/manifest-version-store-file.js.map +1 -0
  65. package/dist/manifest-version-store.d.ts +14 -0
  66. package/dist/manifest-version-store.d.ts.map +1 -0
  67. package/dist/manifest-version-store.js +13 -0
  68. package/dist/manifest-version-store.js.map +1 -0
  69. package/dist/network-directory-node.d.ts +94 -0
  70. package/dist/network-directory-node.d.ts.map +1 -0
  71. package/dist/network-directory-node.js +626 -0
  72. package/dist/network-directory-node.js.map +1 -0
  73. package/dist/nonce-dedup.d.ts +68 -0
  74. package/dist/nonce-dedup.d.ts.map +1 -0
  75. package/dist/nonce-dedup.js +204 -0
  76. package/dist/nonce-dedup.js.map +1 -0
  77. package/dist/notification-dispatcher.d.ts +65 -0
  78. package/dist/notification-dispatcher.d.ts.map +1 -0
  79. package/dist/notification-dispatcher.js +138 -0
  80. package/dist/notification-dispatcher.js.map +1 -0
  81. package/dist/registration-context.d.ts +69 -0
  82. package/dist/registration-context.d.ts.map +1 -0
  83. package/dist/registration-context.js +118 -0
  84. package/dist/registration-context.js.map +1 -0
  85. package/dist/registration-manager.d.ts +72 -0
  86. package/dist/registration-manager.d.ts.map +1 -0
  87. package/dist/registration-manager.js +267 -0
  88. package/dist/registration-manager.js.map +1 -0
  89. package/dist/registration-persistence.d.ts +131 -0
  90. package/dist/registration-persistence.d.ts.map +1 -0
  91. package/dist/registration-persistence.js +233 -0
  92. package/dist/registration-persistence.js.map +1 -0
  93. package/dist/retry-queue.d.ts +144 -0
  94. package/dist/retry-queue.d.ts.map +1 -0
  95. package/dist/retry-queue.js +444 -0
  96. package/dist/retry-queue.js.map +1 -0
  97. package/dist/seal-frontier-verify.d.ts +58 -0
  98. package/dist/seal-frontier-verify.d.ts.map +1 -0
  99. package/dist/seal-frontier-verify.js +87 -0
  100. package/dist/seal-frontier-verify.js.map +1 -0
  101. package/dist/seal-legibility-tbs.d.ts +25 -0
  102. package/dist/seal-legibility-tbs.d.ts.map +1 -0
  103. package/dist/seal-legibility-tbs.js +78 -0
  104. package/dist/seal-legibility-tbs.js.map +1 -0
  105. package/dist/seal-upgrade.d.ts +90 -0
  106. package/dist/seal-upgrade.d.ts.map +1 -0
  107. package/dist/seal-upgrade.js +178 -0
  108. package/dist/seal-upgrade.js.map +1 -0
  109. package/dist/session-assignment-parser.d.ts +22 -0
  110. package/dist/session-assignment-parser.d.ts.map +1 -0
  111. package/dist/session-assignment-parser.js +139 -0
  112. package/dist/session-assignment-parser.js.map +1 -0
  113. package/dist/session-ceremony.d.ts +156 -0
  114. package/dist/session-ceremony.d.ts.map +1 -0
  115. package/dist/session-ceremony.js +447 -0
  116. package/dist/session-ceremony.js.map +1 -0
  117. package/dist/session-connection-gater.d.ts +91 -0
  118. package/dist/session-connection-gater.d.ts.map +1 -0
  119. package/dist/session-connection-gater.js +146 -0
  120. package/dist/session-connection-gater.js.map +1 -0
  121. package/dist/session-node-manager.d.ts +585 -0
  122. package/dist/session-node-manager.d.ts.map +1 -0
  123. package/dist/session-node-manager.js +2609 -0
  124. package/dist/session-node-manager.js.map +1 -0
  125. package/dist/session-relay-client.d.ts +101 -0
  126. package/dist/session-relay-client.d.ts.map +1 -0
  127. package/dist/session-relay-client.js +520 -0
  128. package/dist/session-relay-client.js.map +1 -0
  129. package/dist/session-tree.d.ts +80 -0
  130. package/dist/session-tree.d.ts.map +1 -0
  131. package/dist/session-tree.js +123 -0
  132. package/dist/session-tree.js.map +1 -0
  133. package/dist/signaling-connect.d.ts +83 -0
  134. package/dist/signaling-connect.d.ts.map +1 -0
  135. package/dist/signaling-connect.js +266 -0
  136. package/dist/signaling-connect.js.map +1 -0
  137. package/dist/transcript-cipher.d.ts +31 -0
  138. package/dist/transcript-cipher.d.ts.map +1 -0
  139. package/dist/transcript-cipher.js +74 -0
  140. package/dist/transcript-cipher.js.map +1 -0
  141. package/dist/transport-composition.d.ts +31 -0
  142. package/dist/transport-composition.d.ts.map +1 -0
  143. package/dist/transport-composition.js +55 -0
  144. package/dist/transport-composition.js.map +1 -0
  145. package/dist/transport-selector.d.ts +189 -0
  146. package/dist/transport-selector.d.ts.map +1 -0
  147. package/dist/transport-selector.js +195 -0
  148. package/dist/transport-selector.js.map +1 -0
  149. package/dist/types.d.ts +265 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +33 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +1 -1
@@ -0,0 +1,78 @@
1
+ /**
2
+ * CELLO-M7 — canonical hash of the seal-certificate legibility object, for binding it into
3
+ * the FROST-signed seal TBS (tamper-evidence). MUST stay byte-for-byte identical to the
4
+ * directory's copy (`trustless-cello/packages/directory/src/seal-legibility.ts`
5
+ * canonicalLegibilityHash) — the live bilateral seal SELF-CHECKS agreement: directory and
6
+ * daemon each fold this hash into the signed TBS, and the seal verifies only if they match.
7
+ *
8
+ * Design: an EXPLICIT, fixed byte layout (NOT canonical CBOR) so there is zero dependence on
9
+ * a CBOR library's determinism. Only the TAMPERABLE facts are bound — the per-party frontiers
10
+ * + attestation_mode and the final_message. The constants (attests / implies_assent /
11
+ * disclaimer) are NOT bound: the daemon re-asserts attests/implies_assent as literals on the
12
+ * read surface, so they cannot be meaningfully tampered; the disclaimer is informational.
13
+ *
14
+ * Hash = SHA-256( domain || u32(participantCount) ||
15
+ * for each participant (in array order): pubkey[32] || u32(content_frontier_seq) ||
16
+ * u32(last_authored_seq) || modeByte ||
17
+ * final_message.sender_pubkey[32] || u32(seq) || answeredByte )
18
+ *
19
+ * Participants are hashed in array order, so a MITM that REORDERS the participants array also
20
+ * changes the hash → the seal signature fails. Crypto ref: SHA-256 FIPS 180-4.
21
+ */
22
+ import { createHash } from "node:crypto";
23
+ const DOMAIN = Buffer.from("CELLO-SEAL-LEGIBILITY-v1", "utf8");
24
+ /** Coerce any byte-ish value to a 32-byte Buffer (zero-padded/truncated). Both sides do this. */
25
+ function pubkey32(v) {
26
+ const out = Buffer.alloc(32);
27
+ if (v instanceof Uint8Array)
28
+ Buffer.from(v).copy(out, 0, 0, 32);
29
+ else if (Buffer.isBuffer(v))
30
+ v.copy(out, 0, 0, 32);
31
+ else if (typeof v === "string" && /^[0-9a-fA-F]{64}$/.test(v))
32
+ Buffer.from(v, "hex").copy(out, 0, 0, 32);
33
+ return out;
34
+ }
35
+ /** Coerce to uint32 the SAME way on both sides (handles bigint/number; >>>0 normalises). */
36
+ function u32(v) {
37
+ const n = typeof v === "bigint" ? Number(v) : typeof v === "number" ? v : 0;
38
+ const out = Buffer.alloc(4);
39
+ out.writeUInt32BE((n >>> 0), 0);
40
+ return out;
41
+ }
42
+ function modeByte(v) {
43
+ const b = v === "live" ? 1 : v === "recovered" ? 2 : v === "absent" ? 3 : 0;
44
+ return Buffer.from([b]);
45
+ }
46
+ export function canonicalLegibilityBytes(legibility) {
47
+ const parts = [DOMAIN];
48
+ const participants = Array.isArray(legibility.participants) ? legibility.participants : [];
49
+ const count = Buffer.alloc(4);
50
+ count.writeUInt32BE(participants.length >>> 0, 0);
51
+ parts.push(count);
52
+ for (const p of participants) {
53
+ parts.push(pubkey32(p.pubkey), u32(p.content_frontier_seq), u32(p.last_authored_seq), modeByte(p.attestation_mode));
54
+ }
55
+ const fm = legibility.final_message ?? { sender_pubkey: undefined, seq: 0, answered: false };
56
+ parts.push(pubkey32(fm.sender_pubkey), u32(fm.seq), Buffer.from([fm.answered === true ? 1 : 0]));
57
+ return Buffer.concat(parts);
58
+ }
59
+ /** SHA-256 of the canonical legibility bytes (32 bytes). */
60
+ export function canonicalLegibilityHash(legibility) {
61
+ return new Uint8Array(createHash("sha256").update(canonicalLegibilityBytes(legibility)).digest());
62
+ }
63
+ /**
64
+ * Build the seal TBS bytes WITH the legibility binding: the plain seal TBS concatenated with
65
+ * the 32-byte legibility hash. When `legibility` is absent (the unilateral seal carries none),
66
+ * returns the plain TBS unchanged — so the unilateral path keeps signing/verifying the plain TBS
67
+ * and only the bilateral path (which always carries legibility) is bound.
68
+ */
69
+ export function bindLegibilityToTbs(tbs, legibility) {
70
+ if (!legibility)
71
+ return tbs;
72
+ const h = canonicalLegibilityHash(legibility);
73
+ const out = new Uint8Array(tbs.length + h.length);
74
+ out.set(tbs, 0);
75
+ out.set(h, tbs.length);
76
+ return out;
77
+ }
78
+ //# sourceMappingURL=seal-legibility-tbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal-legibility-tbs.js","sourceRoot":"","sources":["../src/seal-legibility-tbs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ import type { KeyProvider } from "@cello-protocol/crypto";
2
+ import type { Logger } from "./types.js";
3
+ /**
4
+ * Domain separator for the upgrade-ack TBS. B's daemon and the directory MUST build byte-identical
5
+ * bytes — same domain string, same cbor-x encoder options (tagUint8Array:false). Verified identical
6
+ * across both repos (cbor-x 1.6.4). Domain separation prevents replay as any other CELLO signature.
7
+ */
8
+ export declare const SEAL_UPGRADE_ACK_DOMAIN = "cello-seal-upgrade-ack-v1";
9
+ /** The exact upgrade-ack TBS B signs / the directory + present party verify. */
10
+ export declare function buildSealUpgradeAckTbs(sessionId: Uint8Array, sealedRoot: Uint8Array): Uint8Array;
11
+ /** Verifiability of a session for B to ratify a unilateral seal — the SAME bar as the UP-2 auto-ack. */
12
+ export interface SealUpgradeReadiness {
13
+ known: boolean;
14
+ tampered: boolean;
15
+ }
16
+ /**
17
+ * THE KERNEL DECISION. B may sign its ratification ONLY when it genuinely possesses + integrity-
18
+ * verified the content behind R1. Pure + exhaustively unit-tested: a session B has no record of
19
+ * (content_unrecoverable, AC-002) or whose content cross-check flagged tamper (content_tamper,
20
+ * AC-003) is REFUSED. Verified-but-disliked content is NOT a refusal (disagreement ≠ unverifiable).
21
+ */
22
+ export declare function evaluateSealUpgrade(readiness: SealUpgradeReadiness): {
23
+ proceed: true;
24
+ } | {
25
+ proceed: false;
26
+ refuseReason: "content_unrecoverable" | "content_tamper";
27
+ };
28
+ export interface AttemptSealUpgradeDeps {
29
+ logger: Logger;
30
+ agentName: string;
31
+ agentPubkeyHex: string;
32
+ /** B's session verifiability for this session (SessionNodeManager.getSealUpgradeReadiness). */
33
+ getReadiness: (agentName: string, sessionIdHex: string) => SealUpgradeReadiness;
34
+ /**
35
+ * M1: the number of content leaves B holds for this session (SessionNodeManager.getSessionTree
36
+ * (...).size()). R1 has leaf_count leaves = content leaves + A's single SEAL ctrl leaf, so B's
37
+ * content tree must hold at least leaf_count-1 leaves or B is missing content it would over-attest.
38
+ */
39
+ getContentLeafCount: (agentName: string, sessionIdHex: string) => number;
40
+ /** Recover parked content so B holds everything behind R1 before the gate (autoRecoverForAgent). */
41
+ recoverContent: (agentName: string) => Promise<void>;
42
+ /** B's K_local signer for this agent (keyProviders.get). */
43
+ getKeyProvider: (agentName: string) => KeyProvider | undefined;
44
+ /** Send a signaling frame to the directory (signaling.sendRaw). */
45
+ sendRaw: (frame: Record<string, unknown>) => Promise<{
46
+ ok: boolean;
47
+ }>;
48
+ }
49
+ /**
50
+ * THE KERNEL, wired. Recover content → consult the gate → REFUSE (no signature, no request) on
51
+ * content_unrecoverable / content_tamper → else sign the ack over R1 with B's OWN K_local and send
52
+ * seal_upgrade_request. Returns whether a request was sent (and the refuse reason if not) so a unit
53
+ * test asserts the gate is genuinely consulted, not bypassed. Never throws.
54
+ */
55
+ export declare function attemptSealUpgrade(deps: AttemptSealUpgradeDeps, sessionIdHex: string, frame: Record<string, unknown>): Promise<{
56
+ sent: boolean;
57
+ reason?: string;
58
+ }>;
59
+ export interface VerifyUpgradeConfirmedDeps {
60
+ logger: Logger;
61
+ agentName: string;
62
+ agentPubkeyHex: string;
63
+ celloDir: string;
64
+ /**
65
+ * H1: the counterparty pubkey (hex) of the LOCAL session record for sessionIdHex, or null if this
66
+ * agent has no such session. Binds the cert's present/returning pubkeys to the REAL participants so
67
+ * a malicious directory cannot sign the ack with a throwaway key and force a state transition on a
68
+ * session we are in (or push a confirmed frame for a session we never had).
69
+ */
70
+ getCounterpartyHex: (agentName: string, sessionIdHex: string) => string | null;
71
+ }
72
+ /**
73
+ * AC-008 dual-attestation verify, extracted. NEVER trust the directory's "bilateral" claim.
74
+ *
75
+ * - ALWAYS verify the RETURNING attestation (B's ack) over R1 — proves B genuinely ratified, catches
76
+ * a directory that fabricated or swapped B's signature. The load-bearing check (anyone can do it).
77
+ * - If THIS agent is the PRESENT party (A, holds its primary key), ALSO verify the present attestation
78
+ * over the rebuilt seal TBS (leaf_count-bound). The responder (B) cannot (no initiator key).
79
+ *
80
+ * Returns { ok:false, reason } on any malformed/forged cert — the caller must NOT mark the session
81
+ * bilateral in that case. Returns the party so the caller can log accurately.
82
+ */
83
+ export declare function verifyUpgradeConfirmedCert(deps: VerifyUpgradeConfirmedDeps, sessionIdHex: string, frame: Record<string, unknown>): Promise<{
84
+ ok: true;
85
+ party: "present" | "returning";
86
+ } | {
87
+ ok: false;
88
+ reason: string;
89
+ }>;
90
+ //# sourceMappingURL=seal-upgrade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal-upgrade.d.ts","sourceRoot":"","sources":["../src/seal-upgrade.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAGnE,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,GAAG,UAAU,CAEhG;AAMD,wGAAwG;AACxG,MAAM,WAAW,oBAAoB;IAAG,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE;AAE3E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,oBAAoB,GAC9B;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,YAAY,EAAE,uBAAuB,GAAG,gBAAgB,CAAA;CAAE,CAIlG;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,+FAA+F;IAC/F,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,oBAAoB,CAAC;IAChF;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IACzE,oGAAoG;IACpG,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,4DAA4D;IAC5D,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IAC/D,mEAAmE;IACnE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACvE;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,sBAAsB,EAC5B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqE7C;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAChF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,0BAA0B,EAChC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA0DvF"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * CELLO-M7-UPGRADE-001 (DOD-UP-1) — the returning-absent-party seal upgrade, extracted from the
3
+ * daemon so the KERNEL (content-possession gate) and the AC-008 dual-attestation verify run under
4
+ * adversarial unit tests with the REAL bodies (not just the happy path).
5
+ *
6
+ * Model 2: when the previously-ABSENT party B returns, it RATIFIES the existing unilateral sealed
7
+ * root R1 (does NOT re-seal a new root). B signs an ack over CBOR([SEAL_UPGRADE_ACK_DOMAIN,
8
+ * session_id, sealed_root]) with its K_local. The directory verifies it and writes a SUPERSEDING
9
+ * bilateral notarization. Both parties verify the dual-attestation cert before accepting bilateral.
10
+ */
11
+ import { join } from "node:path";
12
+ import { Encoder } from "cbor-x";
13
+ import { verify as ed25519Verify } from "@cello-protocol/crypto";
14
+ import { verifyUnilateralCertificate } from "./session-ceremony.js";
15
+ /**
16
+ * Domain separator for the upgrade-ack TBS. B's daemon and the directory MUST build byte-identical
17
+ * bytes — same domain string, same cbor-x encoder options (tagUint8Array:false). Verified identical
18
+ * across both repos (cbor-x 1.6.4). Domain separation prevents replay as any other CELLO signature.
19
+ */
20
+ export const SEAL_UPGRADE_ACK_DOMAIN = "cello-seal-upgrade-ack-v1";
21
+ const UPGRADE_CBOR_ENC = new Encoder({ tagUint8Array: false });
22
+ /** The exact upgrade-ack TBS B signs / the directory + present party verify. */
23
+ export function buildSealUpgradeAckTbs(sessionId, sealedRoot) {
24
+ return UPGRADE_CBOR_ENC.encode([SEAL_UPGRADE_ACK_DOMAIN, sessionId, sealedRoot]);
25
+ }
26
+ function toU8(v) {
27
+ return v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint8Array(v) : null;
28
+ }
29
+ /**
30
+ * THE KERNEL DECISION. B may sign its ratification ONLY when it genuinely possesses + integrity-
31
+ * verified the content behind R1. Pure + exhaustively unit-tested: a session B has no record of
32
+ * (content_unrecoverable, AC-002) or whose content cross-check flagged tamper (content_tamper,
33
+ * AC-003) is REFUSED. Verified-but-disliked content is NOT a refusal (disagreement ≠ unverifiable).
34
+ */
35
+ export function evaluateSealUpgrade(readiness) {
36
+ if (!readiness.known)
37
+ return { proceed: false, refuseReason: "content_unrecoverable" };
38
+ if (readiness.tampered)
39
+ return { proceed: false, refuseReason: "content_tamper" };
40
+ return { proceed: true };
41
+ }
42
+ /**
43
+ * THE KERNEL, wired. Recover content → consult the gate → REFUSE (no signature, no request) on
44
+ * content_unrecoverable / content_tamper → else sign the ack over R1 with B's OWN K_local and send
45
+ * seal_upgrade_request. Returns whether a request was sent (and the refuse reason if not) so a unit
46
+ * test asserts the gate is genuinely consulted, not bypassed. Never throws.
47
+ */
48
+ export async function attemptSealUpgrade(deps, sessionIdHex, frame) {
49
+ try {
50
+ const sessionId = toU8(frame["session_id"]);
51
+ const sealedRoot = toU8(frame["sealed_root"]);
52
+ const leafCount = typeof frame["leaf_count"] === "number" ? frame["leaf_count"] : null;
53
+ if (!sessionId || !sealedRoot || leafCount === null) {
54
+ deps.logger.warn("session.seal.upgrade.refused", { sessionId: sessionIdHex, reason: "malformed_notification" });
55
+ return { sent: false, reason: "malformed_notification" };
56
+ }
57
+ // B (responder) CANNOT channel-independently verify the unilateral cert's signature — that is the
58
+ // INITIATOR's group key, which B does not hold. B accepts R1 on the AUTHENTICATED daemon↔directory
59
+ // Noise channel (as the responder accepts session_sealed). Its real protection is the gate below;
60
+ // a wrong R1 yields a B-ack that doesn't match A's real seal → no coherent bilateral forms.
61
+ // Recover any parked content so B holds everything behind R1, THEN gate.
62
+ await deps.recoverContent(deps.agentName).catch(() => { });
63
+ const decision = evaluateSealUpgrade(deps.getReadiness(deps.agentName, sessionIdHex));
64
+ if (!decision.proceed) {
65
+ // KERNEL refusal. content_tamper is a SECURITY event (ERROR); content_unrecoverable is WARN.
66
+ const level = decision.refuseReason === "content_tamper" ? "error" : "warn";
67
+ deps.logger[level]("session.seal.upgrade.refused", { sessionId: sessionIdHex, reason: decision.refuseReason });
68
+ return { sent: false, reason: decision.refuseReason };
69
+ }
70
+ // M1 (KERNEL completeness): B must hold the FULL content behind R1, not merely a tamper-free
71
+ // subset. R1 = root over [content leaves..., A's SEAL ctrl leaf], so leaf_count counts the content
72
+ // leaves + 1; B's content tree must hold ≥ leaf_count-1. Refuse if B recovered an INCOMPLETE
73
+ // transcript — never over-attest to content B did not fully receive. (Exact root-reproduction is
74
+ // the deferred MSG-001-3b canonical-sequence reconciliation; this count gate is the interim bar.)
75
+ const contentLeaves = deps.getContentLeafCount(deps.agentName, sessionIdHex);
76
+ if (contentLeaves < leafCount - 1) {
77
+ deps.logger.warn("session.seal.upgrade.refused", {
78
+ sessionId: sessionIdHex, reason: "content_incomplete", have: contentLeaves, need: leafCount - 1,
79
+ });
80
+ return { sent: false, reason: "content_incomplete" };
81
+ }
82
+ // KERNEL passed — sign the ack over R1 with B's OWN K_local and request the upgrade.
83
+ const keyProvider = deps.getKeyProvider(deps.agentName);
84
+ if (!keyProvider) {
85
+ deps.logger.warn("session.seal.upgrade.refused", { sessionId: sessionIdHex, reason: "no_key_provider" });
86
+ return { sent: false, reason: "no_key_provider" };
87
+ }
88
+ const ackTbs = buildSealUpgradeAckTbs(sessionId, sealedRoot);
89
+ const ackSig = new Uint8Array(await keyProvider.sign(ackTbs));
90
+ const returningPubkey = new Uint8Array(Buffer.from(deps.agentPubkeyHex, "hex"));
91
+ const sent = await deps.sendRaw({
92
+ type: "seal_upgrade_request",
93
+ session_id: sessionId,
94
+ returning_pubkey: returningPubkey,
95
+ ack_signature: ackSig,
96
+ // forwarded (from the notification cert) so the directory relays it → the present party rebuilds
97
+ // the seal TBS and verifies its own attestation (AC-008).
98
+ leaf_count: leafCount,
99
+ });
100
+ if (!sent.ok) {
101
+ deps.logger.warn("session.seal.upgrade.refused", { sessionId: sessionIdHex, reason: "request_send_failed" });
102
+ return { sent: false, reason: "request_send_failed" };
103
+ }
104
+ deps.logger.info("session.seal.upgrade.requested", { sessionId: sessionIdHex, agentName: deps.agentName });
105
+ return { sent: true };
106
+ }
107
+ catch (err) {
108
+ deps.logger.warn("session.seal.upgrade.refused", {
109
+ sessionId: sessionIdHex,
110
+ reason: err instanceof Error ? err.message : String(err),
111
+ });
112
+ return { sent: false, reason: "exception" };
113
+ }
114
+ }
115
+ /**
116
+ * AC-008 dual-attestation verify, extracted. NEVER trust the directory's "bilateral" claim.
117
+ *
118
+ * - ALWAYS verify the RETURNING attestation (B's ack) over R1 — proves B genuinely ratified, catches
119
+ * a directory that fabricated or swapped B's signature. The load-bearing check (anyone can do it).
120
+ * - If THIS agent is the PRESENT party (A, holds its primary key), ALSO verify the present attestation
121
+ * over the rebuilt seal TBS (leaf_count-bound). The responder (B) cannot (no initiator key).
122
+ *
123
+ * Returns { ok:false, reason } on any malformed/forged cert — the caller must NOT mark the session
124
+ * bilateral in that case. Returns the party so the caller can log accurately.
125
+ */
126
+ export async function verifyUpgradeConfirmedCert(deps, sessionIdHex, frame) {
127
+ const sessionId = toU8(frame["session_id"]);
128
+ const sealedRoot = toU8(frame["sealed_root"]);
129
+ const leafCount = typeof frame["leaf_count"] === "number" ? frame["leaf_count"] : null;
130
+ const tsRaw = frame["close_timestamp"];
131
+ const closeTs = typeof tsRaw === "number" ? tsRaw : typeof tsRaw === "bigint" ? Number(tsRaw) : null;
132
+ const presentPubkey = toU8(frame["present_pubkey"]);
133
+ const presentSig = toU8(frame["present_signature"]);
134
+ const presentSigType = frame["present_signature_type"];
135
+ const returningPubkey = toU8(frame["returning_pubkey"]);
136
+ const returningSig = toU8(frame["returning_signature"]);
137
+ if (!sessionId || !sealedRoot || leafCount === null || closeTs === null || !presentPubkey ||
138
+ !presentSig || !returningPubkey || !returningSig ||
139
+ (presentSigType !== "frost" && presentSigType !== "single")) {
140
+ deps.logger.warn("session.seal.upgrade.cert.invalid", { sessionId: sessionIdHex, reason: "malformed_confirmed" });
141
+ return { ok: false, reason: "malformed_confirmed" };
142
+ }
143
+ // H1: bind the cert's present/returning pubkeys to the REAL participants of OUR session record.
144
+ // The pair {present, returning} must equal {self, our counterparty}; otherwise a single untrusted
145
+ // directory could sign the ack with an attacker-chosen key and drive a B-side state transition, or
146
+ // push a confirmed frame for a session we never had. We must hold the session locally to accept.
147
+ const presentHex = Buffer.from(presentPubkey).toString("hex");
148
+ const returningHex = Buffer.from(returningPubkey).toString("hex");
149
+ const selfHex = deps.agentPubkeyHex;
150
+ const counterpartyHex = deps.getCounterpartyHex(deps.agentName, sessionIdHex);
151
+ if (!counterpartyHex) {
152
+ deps.logger.warn("session.seal.upgrade.cert.invalid", { sessionId: sessionIdHex, reason: "unknown_session" });
153
+ return { ok: false, reason: "unknown_session" };
154
+ }
155
+ const expected = new Set([selfHex, counterpartyHex]);
156
+ if (presentHex === returningHex || !expected.has(presentHex) || !expected.has(returningHex)) {
157
+ deps.logger.warn("session.seal.upgrade.cert.invalid", { sessionId: sessionIdHex, reason: "participant_mismatch" });
158
+ return { ok: false, reason: "participant_mismatch" };
159
+ }
160
+ // 1. Returning attestation (the returning party's ack) over R1 — the AC-008 kernel. returningPubkey
161
+ // is now proven to be a real participant of this session (self or counterparty), not attacker-chosen.
162
+ const ackTbs = buildSealUpgradeAckTbs(sessionId, sealedRoot);
163
+ if (!ed25519Verify(returningPubkey, ackTbs, returningSig)) {
164
+ deps.logger.warn("session.seal.upgrade.cert.invalid", { sessionId: sessionIdHex, reason: "returning_signature_invalid" });
165
+ return { ok: false, reason: "returning_signature_invalid" };
166
+ }
167
+ // 2. Present attestation (A's seal sig) — only the present party holds the key to verify it.
168
+ const isPresent = selfHex === presentHex;
169
+ if (isPresent) {
170
+ const presentResult = await verifyUnilateralCertificate({ agentDir: join(deps.celloDir, "agents", deps.agentName), agentPubkeyHex: deps.agentPubkeyHex, logger: deps.logger }, { sessionId, sealedRoot, leafCount, closeTimestamp: closeTs, frostSignature: presentSig, signatureType: presentSigType });
171
+ if (!presentResult.ok) {
172
+ deps.logger.warn("session.seal.upgrade.cert.invalid", { sessionId: sessionIdHex, reason: `present_signature_invalid:${presentResult.reason}` });
173
+ return { ok: false, reason: `present_signature_invalid:${presentResult.reason}` };
174
+ }
175
+ }
176
+ return { ok: true, party: isPresent ? "present" : "returning" };
177
+ }
178
+ //# sourceMappingURL=seal-upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal-upgrade.js","sourceRoot":"","sources":["../src/seal-upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Session assignment parsing — ported onto the daemon (DOD-SPINE-5).
3
+ *
4
+ * Decodes a raw CBOR-decoded `assignment` object (from a directory
5
+ * `session_assignment` frame) into a typed SessionAssignment. Shape-validates only;
6
+ * the FROST/single signature is verified downstream by the transport/session layer
7
+ * against the directory's pinned key. This is a faithful port of
8
+ * core/client/src/session-assignment-parser.ts — the daemon must NOT import the dead
9
+ * core/client stack, so the proven logic lives here.
10
+ */
11
+ import type { SessionAssignment } from "@cello-protocol/protocol-types";
12
+ /**
13
+ * Decode a raw CBOR-decoded object (frame["assignment"]) into a typed SessionAssignment.
14
+ * Returns null if any required field is missing or malformed.
15
+ */
16
+ export declare function parseSessionAssignment(raw: Record<string, unknown>): SessionAssignment | null;
17
+ /**
18
+ * Map a raw `session_request_error` frame's reason to a stable negotiator reason code.
19
+ * Distinct cause → distinct code (M7 error discipline); unknown → directory_unreachable.
20
+ */
21
+ export declare function sessionRequestErrorReason(frame: Record<string, unknown>): string;
22
+ //# sourceMappingURL=session-assignment-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-assignment-parser.d.ts","sourceRoot":"","sources":["../src/session-assignment-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAoCxE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,GAAG,IAAI,CA8D7F;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAiBhF"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Session assignment parsing — ported onto the daemon (DOD-SPINE-5).
3
+ *
4
+ * Decodes a raw CBOR-decoded `assignment` object (from a directory
5
+ * `session_assignment` frame) into a typed SessionAssignment. Shape-validates only;
6
+ * the FROST/single signature is verified downstream by the transport/session layer
7
+ * against the directory's pinned key. This is a faithful port of
8
+ * core/client/src/session-assignment-parser.ts — the daemon must NOT import the dead
9
+ * core/client stack, so the proven logic lives here.
10
+ */
11
+ function toU8Safe(v) {
12
+ if (v instanceof Uint8Array)
13
+ return v;
14
+ if (Buffer.isBuffer(v))
15
+ return new Uint8Array(v);
16
+ return null;
17
+ }
18
+ function parseStringArray(v) {
19
+ if (!Array.isArray(v))
20
+ return null;
21
+ if (!v.every((x) => typeof x === "string"))
22
+ return null;
23
+ return v;
24
+ }
25
+ function parseParticipantInfo(raw) {
26
+ if (typeof raw !== "object" || raw === null)
27
+ return null;
28
+ const r = raw;
29
+ const pubkey = toU8Safe(r["pubkey"]);
30
+ if (!pubkey || pubkey.length !== 32)
31
+ return null;
32
+ const peerId = typeof r["peer_id"] === "string" ? r["peer_id"] : null;
33
+ if (!peerId)
34
+ return null;
35
+ const multiaddrs = parseStringArray(r["multiaddrs"]);
36
+ if (!multiaddrs)
37
+ return null;
38
+ return { pubkey, peer_id: peerId, multiaddrs };
39
+ }
40
+ function parseEndpointInfo(raw) {
41
+ if (typeof raw !== "object" || raw === null)
42
+ return null;
43
+ const r = raw;
44
+ const peerId = typeof r["peer_id"] === "string" ? r["peer_id"] : null;
45
+ if (!peerId)
46
+ return null;
47
+ const multiaddrs = parseStringArray(r["multiaddrs"]);
48
+ if (!multiaddrs)
49
+ return null;
50
+ return { peer_id: peerId, multiaddrs };
51
+ }
52
+ /**
53
+ * Decode a raw CBOR-decoded object (frame["assignment"]) into a typed SessionAssignment.
54
+ * Returns null if any required field is missing or malformed.
55
+ */
56
+ export function parseSessionAssignment(raw) {
57
+ const sessionId = toU8Safe(raw["session_id"]);
58
+ if (!sessionId || sessionId.length !== 16)
59
+ return null;
60
+ const dirPubkey = toU8Safe(raw["directory_pubkey"]);
61
+ if (!dirPubkey || dirPubkey.length !== 32)
62
+ return null;
63
+ const dirSig = toU8Safe(raw["directory_signature"]);
64
+ if (!dirSig || dirSig.length !== 64)
65
+ return null;
66
+ const tsRaw = raw["session_timestamp"];
67
+ const sessionTimestamp = typeof tsRaw === "number" ? tsRaw : typeof tsRaw === "bigint" ? Number(tsRaw) : null;
68
+ if (sessionTimestamp === null)
69
+ return null;
70
+ const participantA = parseParticipantInfo(raw["participant_a"]);
71
+ if (!participantA)
72
+ return null;
73
+ const participantB = parseParticipantInfo(raw["participant_b"]);
74
+ if (!participantB)
75
+ return null;
76
+ const relayEndpoint = parseEndpointInfo(raw["relay_endpoint"]);
77
+ if (!relayEndpoint)
78
+ return null;
79
+ const directoryEndpoint = parseEndpointInfo(raw["directory_endpoint"]);
80
+ if (!directoryEndpoint)
81
+ return null;
82
+ const sigType = typeof raw["signature_type"] === "string" ? raw["signature_type"] : "single";
83
+ // M7 WIRE-001: session peer IDs + transport mode (undefined when absent, pre-M7 compat).
84
+ const initiatorSessionPeerId = typeof raw["initiator_session_peer_id"] === "string" && raw["initiator_session_peer_id"] !== ""
85
+ ? raw["initiator_session_peer_id"]
86
+ : undefined;
87
+ const initiatorSessionAddrs = parseStringArray(raw["initiator_session_addrs"]) ?? undefined;
88
+ const counterpartySessionPeerId = typeof raw["counterparty_session_peer_id"] === "string" && raw["counterparty_session_peer_id"] !== ""
89
+ ? raw["counterparty_session_peer_id"]
90
+ : undefined;
91
+ const counterpartySessionAddrs = parseStringArray(raw["counterparty_session_addrs"]) ?? undefined;
92
+ const transportModeRaw = raw["transport_mode"];
93
+ const transportMode = transportModeRaw === "direct" ? "direct" : transportModeRaw === "relay" ? "relay" : undefined;
94
+ const common = {
95
+ session_id: sessionId,
96
+ participant_a: participantA,
97
+ participant_b: participantB,
98
+ relay_endpoint: relayEndpoint,
99
+ directory_endpoint: directoryEndpoint,
100
+ session_timestamp: sessionTimestamp,
101
+ directory_pubkey: dirPubkey,
102
+ directory_signature: dirSig,
103
+ initiator_session_peer_id: initiatorSessionPeerId,
104
+ initiator_session_addrs: initiatorSessionAddrs,
105
+ counterparty_session_peer_id: counterpartySessionPeerId,
106
+ counterparty_session_addrs: counterpartySessionAddrs,
107
+ transport_mode: transportMode,
108
+ };
109
+ if (sigType === "frost") {
110
+ const signerPubkey = toU8Safe(raw["signer_pubkey"]);
111
+ if (!signerPubkey || signerPubkey.length !== 32)
112
+ return null;
113
+ return { ...common, signature_type: "frost", signer_pubkey: signerPubkey };
114
+ }
115
+ return { ...common, signature_type: "single" };
116
+ }
117
+ /**
118
+ * Map a raw `session_request_error` frame's reason to a stable negotiator reason code.
119
+ * Distinct cause → distinct code (M7 error discipline); unknown → directory_unreachable.
120
+ */
121
+ export function sessionRequestErrorReason(frame) {
122
+ const reason = frame["reason"];
123
+ const known = new Set([
124
+ "target_offline",
125
+ "relay_unavailable",
126
+ "frost_signer_not_configured",
127
+ "directory_below_threshold",
128
+ "ceremony_timeout",
129
+ "ceremony_exhausted",
130
+ "ceremony_conflict",
131
+ "not_registered",
132
+ "peer_not_registered",
133
+ "no_connection",
134
+ "connection_id_required",
135
+ "session_request_missing_peer_id",
136
+ ]);
137
+ return typeof reason === "string" && known.has(reason) ? reason : "directory_unreachable";
138
+ }
139
+ //# sourceMappingURL=session-assignment-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-assignment-parser.js","sourceRoot":"","sources":["../src/session-assignment-parser.ts"],"names":[],"mappings":"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"}