@cello-protocol/crypto 0.0.59 → 0.0.60

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.d.ts CHANGED
@@ -17,6 +17,8 @@ export { buildRelayRegistrationTbs, verifyRelayRegistrationSignature } from "./r
17
17
  export { sealToRecipient, openSealed, CONTENT_SEAL_OVERHEAD_BYTES } from "./content-seal.js";
18
18
  export { generateSaltContribution, deriveSessionSalt, saltFingerprint, saltedContentHash, SALT_CONTRIBUTION_BYTES, SALT_FINGERPRINT_BYTES, SESSION_SALT_BYTES, } from "./session-salt.js";
19
19
  export { generateSessionEphemeral, destroySessionEphemeral, deriveSessionSecrets, SESSION_KEY_BYTES, type SessionEphemeral, type SessionSecrets, } from "./session-key-agreement.js";
20
+ export { ephemeralSigningMessage, signSessionEphemeral, verifySessionEphemeral, EPHEMERAL_AUTH_REFUSALS, EPHEMERAL_SIG_BYTES, EPHEMERAL_PUBLIC_BYTES, type EphemeralAuthRefusal, type EphemeralAuthResult, } from "./session-ephemeral-auth.js";
21
+ export { sealSessionContent, openSessionContent, SESSION_CONTENT_SEAL_V1, SESSION_CONTENT_SEAL_OVERHEAD_BYTES, } from "./session-content-seal.js";
20
22
  export type { ManifestVerifyResult, ManifestVerifyDiagnostics, ManifestVerifySkipReason, ManifestVerifySkippedEntry, ConsortiumManifestInput } from "./manifest.js";
21
23
  export { canonicalManifestBody, verifyManifest } from "./manifest.js";
22
24
  export type { PreAuthCapability, PreAuthCapabilityBody, CapabilityVerifyResult, CapabilityVerifyReason } from "./preauth-capability.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -28,6 +28,13 @@ export { generateSaltContribution, deriveSessionSalt, saltFingerprint, saltedCon
28
28
  // hybrid-PQ hook built in. ONE output, the envelope key: the salt is agreed separately above
29
29
  // (Decisions Carried #8), because the key is destroyed at close and the salt outlives the session.
30
30
  export { generateSessionEphemeral, destroySessionEphemeral, deriveSessionSecrets, SESSION_KEY_BYTES, } from "./session-key-agreement.js";
31
+ // DOD-M15-EPHEMERAL-AUTH-1: the throwaway key is SIGNED with the agent's identity and the peer's is
32
+ // verified BEFORE anything is derived from it — without this a relay substitutes both sides' keys
33
+ // and reads everything while both ends see a working conversation. Plus the AEAD that encrypts a
34
+ // message body under the agreed key: distinct from `content-seal.ts`, which seals PARKED content to
35
+ // a long-term identity key and deliberately has no forward secrecy.
36
+ export { ephemeralSigningMessage, signSessionEphemeral, verifySessionEphemeral, EPHEMERAL_AUTH_REFUSALS, EPHEMERAL_SIG_BYTES, EPHEMERAL_PUBLIC_BYTES, } from "./session-ephemeral-auth.js";
37
+ export { sealSessionContent, openSessionContent, SESSION_CONTENT_SEAL_V1, SESSION_CONTENT_SEAL_OVERHEAD_BYTES, } from "./session-content-seal.js";
31
38
  export { canonicalManifestBody, verifyManifest } from "./manifest.js";
32
39
  export { canonicalCapabilityBody, signCapability, verifyCapability, encodeCapability, decodeCapability } from "./preauth-capability.js";
33
40
  export { CONSORTIUM_ROOT_KEYS, CONSORTIUM_THRESHOLD, TEST_CONSORTIUM_ROOT_KEYS, TEST_CONSORTIUM_THRESHOLD, } from "./consortium-keys.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEpI,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,SAAS,EACT,WAAW,EACX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAExI,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAU3F,OAAO,EACL,6BAA6B,EAC7B,YAAY,EACZ,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,iGAAiG;AACjG,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,uGAAuG;AACvG,0FAA0F;AAC1F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,YAAY,GACb,MAAM,4BAA4B,CAAC;AAEpC,8FAA8F;AAC9F,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,mCAAmC,CAAC;AAE3C,qGAAqG;AACrG,mGAAmG;AACnG,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,8EAA8E;AAC9E,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,oEAAoE;AACpE,OAAO,EAAE,yBAAyB,EAAE,gCAAgC,EAAE,MAAM,yBAAyB,CAAC;AAEtG,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAC7F,kGAAkG;AAClG,oGAAoG;AACpG,sGAAsG;AACtG,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,kGAAkG;AAClG,6FAA6F;AAC7F,mGAAmG;AACnG,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,GAGlB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACxI,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE3F,wEAAwE;AACxE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEpI,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,SAAS,EACT,WAAW,EACX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAExI,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAU3F,OAAO,EACL,6BAA6B,EAC7B,YAAY,EACZ,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,iGAAiG;AACjG,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,uGAAuG;AACvG,0FAA0F;AAC1F,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,YAAY,GACb,MAAM,4BAA4B,CAAC;AAEpC,8FAA8F;AAC9F,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,mCAAmC,CAAC;AAE3C,qGAAqG;AACrG,mGAAmG;AACnG,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,8EAA8E;AAC9E,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,oEAAoE;AACpE,OAAO,EAAE,yBAAyB,EAAE,gCAAgC,EAAE,MAAM,yBAAyB,CAAC;AAEtG,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAC7F,kGAAkG;AAClG,oGAAoG;AACpG,sGAAsG;AACtG,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,kGAAkG;AAClG,6FAA6F;AAC7F,mGAAmG;AACnG,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,GAGlB,MAAM,4BAA4B,CAAC;AAEpC,oGAAoG;AACpG,kGAAkG;AAClG,iGAAiG;AACjG,oGAAoG;AACpG,oEAAoE;AACpE,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GAGvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,mCAAmC,GACpC,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACxI,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE3F,wEAAwE;AACxE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-test-fixture.d.ts","sourceRoot":"","sources":["../src/manifest-test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAM3F,CAAC;AAEX,sGAAsG;AACtG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,kBAAkB,EAAE,EAC3B,IAAI,CAAC,EAAE,oBAAoB,GAC1B,uBAAuB,CAoBzB;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B;;;CAG9B,CAAC"}
1
+ {"version":3,"file":"manifest-test-fixture.d.ts","sourceRoot":"","sources":["../src/manifest-test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAM3F,CAAC;AAEX,sGAAsG;AACtG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,kBAAkB,EAAE,EAC3B,IAAI,CAAC,EAAE,oBAAoB,GAC1B,uBAAuB,CA+BzB;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B;;;CAG9B,CAAC"}
@@ -34,7 +34,18 @@ export function makeTestManifest(nodes, opts) {
34
34
  const manifest = {
35
35
  version: opts?.version ?? 1,
36
36
  not_before: opts?.notBefore ?? "2026-01-01T00:00:00Z",
37
- expires: opts?.expires ?? "2027-01-01T00:00:00Z",
37
+ /**
38
+ * ⚠️ A FIXTURE THAT EXPIRES IS A TEST SUITE WITH A FUSE. This defaulted to `2027-01-01`, four
39
+ * months out when it was found (2026-08-24) — after which every default-fixture manifest becomes
40
+ * EXPIRED and every test that needs an in-window one goes red **on a date, with no code change**.
41
+ * It would also have silently switched on the lapsed-manifest branches added by
42
+ * `DOD-M15-EXPIRY-CONSUMER-POLICY-1` for every existing verifier test at the same moment.
43
+ *
44
+ * Far-future and FIXED, not `Date.now() + 1y`: a rolling default makes the fixture's window
45
+ * depend on the clock, and the tests that care about window boundaries pass their own dates
46
+ * anyway — which is the reason this default only ever needs to mean "in window".
47
+ */
48
+ expires: opts?.expires ?? "2099-01-01T00:00:00Z",
38
49
  nodes: nodes,
39
50
  signatures: [],
40
51
  };
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-test-fixture.js","sourceRoot":"","sources":["../src/manifest-test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA0E;IACvG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CACrB,CAAC;AAqBX;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAA2B,EAC3B,IAA2B;IAE3B,MAAM,QAAQ,GAA4B;QACxC,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC;QAC3B,UAAU,EAAE,IAAI,EAAE,SAAS,IAAI,sBAAsB;QACrD,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,sBAAsB;QAChD,KAAK,EAAE,KAA2C;QAClD,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,qCAAqC;IACrC,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAE7C,sDAAsD;IACtD,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACzC,YAAY,EAAE,GAAG;QACjB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;KACpF,CAAC,CAAC,CAAC;IAEJ,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,aAAa,EAAE,kEAAkE;IACjF,YAAY,EAAE,kEAAkE;CACxE,CAAC"}
1
+ {"version":3,"file":"manifest-test-fixture.js","sourceRoot":"","sources":["../src/manifest-test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA0E;IACvG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CACrB,CAAC;AAqBX;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAA2B,EAC3B,IAA2B;IAE3B,MAAM,QAAQ,GAA4B;QACxC,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC;QAC3B,UAAU,EAAE,IAAI,EAAE,SAAS,IAAI,sBAAsB;QACrD;;;;;;;;;;WAUG;QACH,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,sBAAsB;QAChD,KAAK,EAAE,KAA2C;QAClD,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,qCAAqC;IACrC,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAE7C,sDAAsD;IACtD,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACzC,YAAY,EAAE,GAAG;QACjB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;KACpF,CAAC,CAAC,CAAC;IAEJ,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,aAAa,EAAE,kEAAkE;IACjF,YAAY,EAAE,kEAAkE;CACxE,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * DOD-M15-EPHEMERAL-AUTH-1 — encrypting a message body under the AGREED SESSION KEY.
3
+ *
4
+ * ─── What this is for, and how it differs from `content-seal.ts` ───────────────────────────────
5
+ *
6
+ * Two encryption schemes exist in this codebase and they are NOT interchangeable. Which one applies
7
+ * is decided by the ROUTE a message takes, and getting that wrong is silent:
8
+ *
9
+ * **This file — LIVE messages.** Encrypted under the per-session key both sides agreed from
10
+ * throwaway keypairs (`session-key-agreement.ts`). Those keypairs are destroyed when the session
11
+ * ends, so a recording of the traffic cannot be decrypted later even if both agents' long-term
12
+ * identity keys are eventually compromised. That is forward secrecy, and it is the whole point.
13
+ *
14
+ * **`content-seal.ts` — PARKED messages.** Encrypted to the recipient's LONG-TERM identity key,
15
+ * because the recipient is offline and cannot take part in a handshake. It has no forward secrecy
16
+ * by construction: whoever holds that identity key can open every message ever sealed to it. That
17
+ * is an accepted trade for the mailbox and must not be copied here.
18
+ *
19
+ * ⚠️ A message that fails live delivery falls back to the mailbox, so the SAME message can take
20
+ * either scheme. The caller must encrypt the copy that goes on the wire and leave the plaintext it
21
+ * holds for the park backstop alone — sealing an already-encrypted body to the identity key gives
22
+ * the recipient bytes locked under a session key that is about to be destroyed.
23
+ *
24
+ * ─── Construction (SPARC Phase P) ──────────────────────────────────────────────────────────────
25
+ *
26
+ * sealSessionContent(key, plaintext):
27
+ * 1. iv = random 12 bytes # NIST SP 800-38D §8.2.2
28
+ * 2. ct||tag = AES-256-GCM(key, iv, plaintext) # NIST SP 800-38D
29
+ * 3. blob = VERSION(1) || iv(12) || ct || tag(16)
30
+ *
31
+ * openSessionContent(key, blob) -> plaintext | null
32
+ *
33
+ * AES-256-GCM matches `content-seal.ts` rather than introducing a second AEAD, so there is one
34
+ * primitive to reason about. RFCs: HKDF — RFC 5869 (upstream, in the key agreement); AES-GCM — NIST
35
+ * SP 800-38D.
36
+ *
37
+ * ─── Why a RANDOM IV rather than a counter ─────────────────────────────────────────────────────
38
+ *
39
+ * A counter is the stronger construction and it needs state that survives a restart. This session
40
+ * key does not: the secret is deliberately never persisted, and a revived session RE-KEYS
41
+ * (Decisions Carried #5), so a counter would restart at zero under a NEW key — which is safe, and
42
+ * would also have to be proven safe at every future change to the revival rule. A 96-bit random IV
43
+ * under a key that lives for one session, with a birthday bound around 2^32 messages, is not the
44
+ * limiting factor here and needs no state at all.
45
+ *
46
+ * ─── The VERSION byte is FRAMING, not compatibility ────────────────────────────────────────────
47
+ *
48
+ * There are no other builds to be compatible with — CELLO is pre-launch with no external installs —
49
+ * so this byte is not here to interoperate with anything. It is here because the alternative is a
50
+ * blob whose layout is implied by its length, and a reader that meets bytes it cannot frame would
51
+ * then hand attacker-chosen input to a decryptor under a guessed layout. One byte, one comparison,
52
+ * and an unknown value REFUSES rather than parsing.
53
+ *
54
+ * That is the only justification, and it is worth stating because the tempting one — "so a future
55
+ * version can change the format" — would be exactly the speculative scaffolding this codebase has
56
+ * ruled against building.
57
+ */
58
+ /**
59
+ * The only version this build writes, and the only one it reads.
60
+ *
61
+ * `0x01` rather than `0x00`: a zero first byte is what an all-zero buffer and a truncated read both
62
+ * look like, so a version of zero cannot be told from an absent one.
63
+ */
64
+ export declare const SESSION_CONTENT_SEAL_V1 = 1;
65
+ /** Bytes added to every message: version + IV + tag. */
66
+ export declare const SESSION_CONTENT_SEAL_OVERHEAD_BYTES: number;
67
+ /**
68
+ * Encrypt a message body under the agreed session key.
69
+ *
70
+ * Throws on a wrong-width key rather than deriving from whatever it was given: a short key silently
71
+ * accepted is encryption that appears to work under something that is not the agreed secret.
72
+ */
73
+ export declare function sealSessionContent(key: Uint8Array, plaintext: Uint8Array): Uint8Array;
74
+ /**
75
+ * Decrypt a message body under the agreed session key.
76
+ *
77
+ * **Returns `null` on every failure and never throws** — wrong key, tampered ciphertext, truncated
78
+ * blob, unknown version. The caller cannot tell those apart and must not try: GCM's tag check is the
79
+ * only thing that distinguishes "not for us" from "modified in flight", and a caller that branched
80
+ * on the difference would be branching on attacker-controlled input.
81
+ *
82
+ * The caller's job on `null` is to refuse the message loudly, not to retry or to fall back to
83
+ * reading it as plaintext.
84
+ */
85
+ export declare function openSessionContent(key: Uint8Array, blob: Uint8Array): Uint8Array | null;
86
+ //# sourceMappingURL=session-content-seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-content-seal.d.ts","sourceRoot":"","sources":["../src/session-content-seal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAWH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,IAAO,CAAC;AAE5C,wDAAwD;AACxD,eAAO,MAAM,mCAAmC,QAA2B,CAAC;AAE5E;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAerF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAiBvF"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * DOD-M15-EPHEMERAL-AUTH-1 — encrypting a message body under the AGREED SESSION KEY.
3
+ *
4
+ * ─── What this is for, and how it differs from `content-seal.ts` ───────────────────────────────
5
+ *
6
+ * Two encryption schemes exist in this codebase and they are NOT interchangeable. Which one applies
7
+ * is decided by the ROUTE a message takes, and getting that wrong is silent:
8
+ *
9
+ * **This file — LIVE messages.** Encrypted under the per-session key both sides agreed from
10
+ * throwaway keypairs (`session-key-agreement.ts`). Those keypairs are destroyed when the session
11
+ * ends, so a recording of the traffic cannot be decrypted later even if both agents' long-term
12
+ * identity keys are eventually compromised. That is forward secrecy, and it is the whole point.
13
+ *
14
+ * **`content-seal.ts` — PARKED messages.** Encrypted to the recipient's LONG-TERM identity key,
15
+ * because the recipient is offline and cannot take part in a handshake. It has no forward secrecy
16
+ * by construction: whoever holds that identity key can open every message ever sealed to it. That
17
+ * is an accepted trade for the mailbox and must not be copied here.
18
+ *
19
+ * ⚠️ A message that fails live delivery falls back to the mailbox, so the SAME message can take
20
+ * either scheme. The caller must encrypt the copy that goes on the wire and leave the plaintext it
21
+ * holds for the park backstop alone — sealing an already-encrypted body to the identity key gives
22
+ * the recipient bytes locked under a session key that is about to be destroyed.
23
+ *
24
+ * ─── Construction (SPARC Phase P) ──────────────────────────────────────────────────────────────
25
+ *
26
+ * sealSessionContent(key, plaintext):
27
+ * 1. iv = random 12 bytes # NIST SP 800-38D §8.2.2
28
+ * 2. ct||tag = AES-256-GCM(key, iv, plaintext) # NIST SP 800-38D
29
+ * 3. blob = VERSION(1) || iv(12) || ct || tag(16)
30
+ *
31
+ * openSessionContent(key, blob) -> plaintext | null
32
+ *
33
+ * AES-256-GCM matches `content-seal.ts` rather than introducing a second AEAD, so there is one
34
+ * primitive to reason about. RFCs: HKDF — RFC 5869 (upstream, in the key agreement); AES-GCM — NIST
35
+ * SP 800-38D.
36
+ *
37
+ * ─── Why a RANDOM IV rather than a counter ─────────────────────────────────────────────────────
38
+ *
39
+ * A counter is the stronger construction and it needs state that survives a restart. This session
40
+ * key does not: the secret is deliberately never persisted, and a revived session RE-KEYS
41
+ * (Decisions Carried #5), so a counter would restart at zero under a NEW key — which is safe, and
42
+ * would also have to be proven safe at every future change to the revival rule. A 96-bit random IV
43
+ * under a key that lives for one session, with a birthday bound around 2^32 messages, is not the
44
+ * limiting factor here and needs no state at all.
45
+ *
46
+ * ─── The VERSION byte is FRAMING, not compatibility ────────────────────────────────────────────
47
+ *
48
+ * There are no other builds to be compatible with — CELLO is pre-launch with no external installs —
49
+ * so this byte is not here to interoperate with anything. It is here because the alternative is a
50
+ * blob whose layout is implied by its length, and a reader that meets bytes it cannot frame would
51
+ * then hand attacker-chosen input to a decryptor under a guessed layout. One byte, one comparison,
52
+ * and an unknown value REFUSES rather than parsing.
53
+ *
54
+ * That is the only justification, and it is worth stating because the tempting one — "so a future
55
+ * version can change the format" — would be exactly the speculative scaffolding this codebase has
56
+ * ruled against building.
57
+ */
58
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
59
+ /** AES-256. */
60
+ const KEY_BYTES = 32;
61
+ /** GCM's standard nonce length (NIST SP 800-38D §8.2). */
62
+ const IV_BYTES = 12;
63
+ /** GCM tag. Full length, never truncated. */
64
+ const TAG_BYTES = 16;
65
+ /**
66
+ * The only version this build writes, and the only one it reads.
67
+ *
68
+ * `0x01` rather than `0x00`: a zero first byte is what an all-zero buffer and a truncated read both
69
+ * look like, so a version of zero cannot be told from an absent one.
70
+ */
71
+ export const SESSION_CONTENT_SEAL_V1 = 0x01;
72
+ /** Bytes added to every message: version + IV + tag. */
73
+ export const SESSION_CONTENT_SEAL_OVERHEAD_BYTES = 1 + IV_BYTES + TAG_BYTES;
74
+ /**
75
+ * Encrypt a message body under the agreed session key.
76
+ *
77
+ * Throws on a wrong-width key rather than deriving from whatever it was given: a short key silently
78
+ * accepted is encryption that appears to work under something that is not the agreed secret.
79
+ */
80
+ export function sealSessionContent(key, plaintext) {
81
+ if (key.length !== KEY_BYTES) {
82
+ throw new Error(`SESSION CONTENT SEAL: the session key must be ${KEY_BYTES} bytes, got ${key.length}. This is a ` +
83
+ "LOCAL defect — the key comes from this side's own agreement, not from the peer. Refusing " +
84
+ "rather than encrypting under something that is not the agreed secret.");
85
+ }
86
+ const iv = new Uint8Array(randomBytes(IV_BYTES));
87
+ const cipher = createCipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
88
+ const ct = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
89
+ const tag = cipher.getAuthTag();
90
+ return new Uint8Array(Buffer.concat([Buffer.from([SESSION_CONTENT_SEAL_V1]), Buffer.from(iv), ct, tag]));
91
+ }
92
+ /**
93
+ * Decrypt a message body under the agreed session key.
94
+ *
95
+ * **Returns `null` on every failure and never throws** — wrong key, tampered ciphertext, truncated
96
+ * blob, unknown version. The caller cannot tell those apart and must not try: GCM's tag check is the
97
+ * only thing that distinguishes "not for us" from "modified in flight", and a caller that branched
98
+ * on the difference would be branching on attacker-controlled input.
99
+ *
100
+ * The caller's job on `null` is to refuse the message loudly, not to retry or to fall back to
101
+ * reading it as plaintext.
102
+ */
103
+ export function openSessionContent(key, blob) {
104
+ if (key.length !== KEY_BYTES)
105
+ return null;
106
+ // A blob must have room for version + IV + tag, and one byte cannot be assumed present: an empty
107
+ // frame would otherwise index past the end and read `undefined` as a version.
108
+ if (blob.length < SESSION_CONTENT_SEAL_OVERHEAD_BYTES)
109
+ return null;
110
+ if (blob[0] !== SESSION_CONTENT_SEAL_V1)
111
+ return null;
112
+ const iv = blob.subarray(1, 1 + IV_BYTES);
113
+ const ct = blob.subarray(1 + IV_BYTES, blob.length - TAG_BYTES);
114
+ const tag = blob.subarray(blob.length - TAG_BYTES);
115
+ try {
116
+ const decipher = createDecipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
117
+ decipher.setAuthTag(Buffer.from(tag));
118
+ return new Uint8Array(Buffer.concat([decipher.update(Buffer.from(ct)), decipher.final()]));
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ }
124
+ //# sourceMappingURL=session-content-seal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-content-seal.js","sourceRoot":"","sources":["../src/session-content-seal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * DOD-M15-EPHEMERAL-AUTH-1 — binding the throwaway key to the agent's identity.
3
+ *
4
+ * ─── The attack this closes, step by step ──────────────────────────────────────────────────────
5
+ *
6
+ * The key agreement mixes two throwaway keys into a shared secret, and the secret itself never
7
+ * crosses the wire. But if nobody SIGNS the throwaway key, an arriving one carries no evidence of
8
+ * who sent it:
9
+ *
10
+ * 1. Alice sends her throwaway public key. The relay is carrying the traffic.
11
+ * 2. The relay keeps Alice's and forwards its OWN key to Bob instead.
12
+ * 3. It does the same in the other direction.
13
+ * 4. It now shares one secret with Alice and a different one with Bob.
14
+ * 5. It decrypts everything, reads it, re-encrypts it, and passes it on. Neither side sees
15
+ * anything wrong, because both halves of the conversation decrypt perfectly.
16
+ *
17
+ * So the unauthenticated layer stops a PASSIVE recorder — which is what harvest-now-decrypt-later
18
+ * is about — and does nothing against the party actually carrying the messages. **And we run the
19
+ * relays**, so without this the guarantee reduces to "trust us", which is the one thing CELLO exists
20
+ * so nobody has to do.
21
+ *
22
+ * ─── What is signed, and why the session id is in it ───────────────────────────────────────────
23
+ *
24
+ * message = "cello/session/v1/ephemeral" || sessionId || ephemeralPublic
25
+ *
26
+ * The LABEL makes this signature unusable as any other kind of CELLO signature, and vice versa: an
27
+ * agent signs many things, and a signature that is valid in two contexts is a signature an attacker
28
+ * can move between them.
29
+ *
30
+ * The SESSION ID binds the ephemeral to the conversation it was minted for. Without it, a signed
31
+ * ephemeral captured from one session could be replayed into another between the same two agents —
32
+ * the signature verifies, both sides derive, and the relay that replayed it knows the secret from
33
+ * the session it harvested. The session id is length-prefixed so that `sessionId ‖ ephemeral` cannot
34
+ * be re-split at a different point to produce the same bytes from different inputs.
35
+ *
36
+ * ⚠️ WHAT THIS DOES NOT DO. It proves the ephemeral came from the holder of that identity key. It
37
+ * does not prove the identity key is the agent you meant to talk to — that is the counterparty
38
+ * identity the caller passes in, and the caller must take it from what the OPERATOR asked for, never
39
+ * from a value the directory or the relay handed back. Verifying against a key the attacker chose is
40
+ * relocating the trust rather than closing it.
41
+ */
42
+ /** Ed25519 signatures are 64 bytes; X25519 publics are 32. */
43
+ export declare const EPHEMERAL_SIG_BYTES = 64;
44
+ export declare const EPHEMERAL_PUBLIC_BYTES = 32;
45
+ /**
46
+ * The exact bytes both sides sign and verify.
47
+ *
48
+ * Written once and used by BOTH directions on purpose. A signer and a verifier that each build the
49
+ * message from their own reading of a spec is how two implementations end up disagreeing about a
50
+ * byte and rejecting each other for a reason neither can see.
51
+ */
52
+ export declare function ephemeralSigningMessage(sessionId: Uint8Array, ephemeralPublic: Uint8Array): Uint8Array;
53
+ /** Sign this side's throwaway public key with the agent's long-term identity key. */
54
+ export declare function signSessionEphemeral(signer: {
55
+ sign(data: Uint8Array): Promise<Uint8Array>;
56
+ }, sessionId: Uint8Array, ephemeralPublic: Uint8Array): Promise<Uint8Array>;
57
+ /**
58
+ * Why a peer's ephemeral was refused. A CLOSED set — a free-form string is what lets a new code
59
+ * reach a caller with nothing to act on (`refusal-reasons.ts` records what that cost).
60
+ */
61
+ export declare const EPHEMERAL_AUTH_REFUSALS: {
62
+ /** No signature at all. */
63
+ readonly SIGNATURE_MISSING: "ephemeral_signature_missing";
64
+ /** Present but the wrong width, or the public key is the wrong width. */
65
+ readonly MALFORMED: "ephemeral_malformed";
66
+ /** Verified against the expected identity and did not match. */
67
+ readonly SIGNATURE_MISMATCH: "ephemeral_signature_mismatch";
68
+ };
69
+ export type EphemeralAuthRefusal = (typeof EPHEMERAL_AUTH_REFUSALS)[keyof typeof EPHEMERAL_AUTH_REFUSALS];
70
+ export type EphemeralAuthResult = {
71
+ ok: true;
72
+ } | {
73
+ ok: false;
74
+ reason: EphemeralAuthRefusal;
75
+ detail: string;
76
+ };
77
+ /**
78
+ * VERIFY A PEER'S EPHEMERAL BEFORE ANYTHING IS DERIVED FROM IT.
79
+ *
80
+ * 🚨 MISSING, MALFORMED AND MISMATCHED ALL FAIL. They are separate REASONS because they send an
81
+ * operator to different places, and they are the same OUTCOME because an attacker evading a mismatch
82
+ * check simply supplies no signature at all. "We could not tell" must never be more forgiving than
83
+ * "we proved it wrong" — that is the hole, not the mismatch.
84
+ *
85
+ * Called BEFORE `deriveSessionSecrets`, never alongside it. Deriving first and checking after means
86
+ * a key exists, briefly, that was agreed with someone unproven — and every "briefly" in this
87
+ * codebase eventually turns out to be long enough for something to read it.
88
+ */
89
+ export declare function verifySessionEphemeral(opts: {
90
+ /** The identity we EXPECT — from what the operator asked for, never from the directory or relay. */
91
+ expectedIdentityPublic: Uint8Array;
92
+ sessionId: Uint8Array;
93
+ peerEphemeralPublic: Uint8Array | undefined;
94
+ peerSignature: Uint8Array | undefined;
95
+ }): EphemeralAuthResult;
96
+ //# sourceMappingURL=session-ephemeral-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-ephemeral-auth.d.ts","sourceRoot":"","sources":["../src/session-ephemeral-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AASH,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,GAAG,UAAU,CActG;AAED,qFAAqF;AACrF,wBAAsB,oBAAoB,CACxC,MAAM,EAAE;IAAE,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAAE,EACvD,SAAS,EAAE,UAAU,EACrB,eAAe,EAAE,UAAU,GAC1B,OAAO,CAAC,UAAU,CAAC,CAErB;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB;IAClC,2BAA2B;;IAE3B,yEAAyE;;IAEzE,gEAAgE;;CAExD,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,OAAO,uBAAuB,CAAC,CAAC;AAEzE,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,oGAAoG;IACpG,sBAAsB,EAAE,UAAU,CAAC;IACnC,SAAS,EAAE,UAAU,CAAC;IACtB,mBAAmB,EAAE,UAAU,GAAG,SAAS,CAAC;IAC5C,aAAa,EAAE,UAAU,GAAG,SAAS,CAAC;CACvC,GAAG,mBAAmB,CAwCtB"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * DOD-M15-EPHEMERAL-AUTH-1 — binding the throwaway key to the agent's identity.
3
+ *
4
+ * ─── The attack this closes, step by step ──────────────────────────────────────────────────────
5
+ *
6
+ * The key agreement mixes two throwaway keys into a shared secret, and the secret itself never
7
+ * crosses the wire. But if nobody SIGNS the throwaway key, an arriving one carries no evidence of
8
+ * who sent it:
9
+ *
10
+ * 1. Alice sends her throwaway public key. The relay is carrying the traffic.
11
+ * 2. The relay keeps Alice's and forwards its OWN key to Bob instead.
12
+ * 3. It does the same in the other direction.
13
+ * 4. It now shares one secret with Alice and a different one with Bob.
14
+ * 5. It decrypts everything, reads it, re-encrypts it, and passes it on. Neither side sees
15
+ * anything wrong, because both halves of the conversation decrypt perfectly.
16
+ *
17
+ * So the unauthenticated layer stops a PASSIVE recorder — which is what harvest-now-decrypt-later
18
+ * is about — and does nothing against the party actually carrying the messages. **And we run the
19
+ * relays**, so without this the guarantee reduces to "trust us", which is the one thing CELLO exists
20
+ * so nobody has to do.
21
+ *
22
+ * ─── What is signed, and why the session id is in it ───────────────────────────────────────────
23
+ *
24
+ * message = "cello/session/v1/ephemeral" || sessionId || ephemeralPublic
25
+ *
26
+ * The LABEL makes this signature unusable as any other kind of CELLO signature, and vice versa: an
27
+ * agent signs many things, and a signature that is valid in two contexts is a signature an attacker
28
+ * can move between them.
29
+ *
30
+ * The SESSION ID binds the ephemeral to the conversation it was minted for. Without it, a signed
31
+ * ephemeral captured from one session could be replayed into another between the same two agents —
32
+ * the signature verifies, both sides derive, and the relay that replayed it knows the secret from
33
+ * the session it harvested. The session id is length-prefixed so that `sessionId ‖ ephemeral` cannot
34
+ * be re-split at a different point to produce the same bytes from different inputs.
35
+ *
36
+ * ⚠️ WHAT THIS DOES NOT DO. It proves the ephemeral came from the holder of that identity key. It
37
+ * does not prove the identity key is the agent you meant to talk to — that is the counterparty
38
+ * identity the caller passes in, and the caller must take it from what the OPERATOR asked for, never
39
+ * from a value the directory or the relay handed back. Verifying against a key the attacker chose is
40
+ * relocating the trust rather than closing it.
41
+ */
42
+ import { verify as edVerify } from "./ed25519.js";
43
+ const ENC = new TextEncoder();
44
+ /** Domain separation. Versioned, so a future change is a new label rather than a reinterpretation. */
45
+ const EPHEMERAL_SIG_LABEL = ENC.encode("cello/session/v1/ephemeral");
46
+ /** Ed25519 signatures are 64 bytes; X25519 publics are 32. */
47
+ export const EPHEMERAL_SIG_BYTES = 64;
48
+ export const EPHEMERAL_PUBLIC_BYTES = 32;
49
+ /**
50
+ * The exact bytes both sides sign and verify.
51
+ *
52
+ * Written once and used by BOTH directions on purpose. A signer and a verifier that each build the
53
+ * message from their own reading of a spec is how two implementations end up disagreeing about a
54
+ * byte and rejecting each other for a reason neither can see.
55
+ */
56
+ export function ephemeralSigningMessage(sessionId, ephemeralPublic) {
57
+ // The session id is LENGTH-PREFIXED (4 bytes, big-endian). Concatenating two variable-length
58
+ // fields lets a crafted pair re-split at a different boundary and produce identical bytes from
59
+ // different inputs — the signature would then cover something other than what it appears to.
60
+ const out = new Uint8Array(EPHEMERAL_SIG_LABEL.length + 4 + sessionId.length + ephemeralPublic.length);
61
+ let o = 0;
62
+ out.set(EPHEMERAL_SIG_LABEL, o);
63
+ o += EPHEMERAL_SIG_LABEL.length;
64
+ out[o++] = (sessionId.length >>> 24) & 0xff;
65
+ out[o++] = (sessionId.length >>> 16) & 0xff;
66
+ out[o++] = (sessionId.length >>> 8) & 0xff;
67
+ out[o++] = sessionId.length & 0xff;
68
+ out.set(sessionId, o);
69
+ o += sessionId.length;
70
+ out.set(ephemeralPublic, o);
71
+ return out;
72
+ }
73
+ /** Sign this side's throwaway public key with the agent's long-term identity key. */
74
+ export async function signSessionEphemeral(signer, sessionId, ephemeralPublic) {
75
+ return signer.sign(ephemeralSigningMessage(sessionId, ephemeralPublic));
76
+ }
77
+ /**
78
+ * Why a peer's ephemeral was refused. A CLOSED set — a free-form string is what lets a new code
79
+ * reach a caller with nothing to act on (`refusal-reasons.ts` records what that cost).
80
+ */
81
+ export const EPHEMERAL_AUTH_REFUSALS = {
82
+ /** No signature at all. */
83
+ SIGNATURE_MISSING: "ephemeral_signature_missing",
84
+ /** Present but the wrong width, or the public key is the wrong width. */
85
+ MALFORMED: "ephemeral_malformed",
86
+ /** Verified against the expected identity and did not match. */
87
+ SIGNATURE_MISMATCH: "ephemeral_signature_mismatch",
88
+ };
89
+ /**
90
+ * VERIFY A PEER'S EPHEMERAL BEFORE ANYTHING IS DERIVED FROM IT.
91
+ *
92
+ * 🚨 MISSING, MALFORMED AND MISMATCHED ALL FAIL. They are separate REASONS because they send an
93
+ * operator to different places, and they are the same OUTCOME because an attacker evading a mismatch
94
+ * check simply supplies no signature at all. "We could not tell" must never be more forgiving than
95
+ * "we proved it wrong" — that is the hole, not the mismatch.
96
+ *
97
+ * Called BEFORE `deriveSessionSecrets`, never alongside it. Deriving first and checking after means
98
+ * a key exists, briefly, that was agreed with someone unproven — and every "briefly" in this
99
+ * codebase eventually turns out to be long enough for something to read it.
100
+ */
101
+ export function verifySessionEphemeral(opts) {
102
+ if (opts.peerSignature === undefined) {
103
+ return {
104
+ ok: false,
105
+ reason: EPHEMERAL_AUTH_REFUSALS.SIGNATURE_MISSING,
106
+ detail: "the peer sent a session key with no signature over it, so there is nothing to tie it to " +
107
+ "your counterparty. An unsigned key is exactly what a relay substituting its own would send, " +
108
+ "and it is refused on the same path as a wrong signature — a check that is lenient about a " +
109
+ "missing proof is a check an attacker skips.",
110
+ };
111
+ }
112
+ if (opts.peerSignature.length !== EPHEMERAL_SIG_BYTES ||
113
+ opts.peerEphemeralPublic === undefined ||
114
+ opts.peerEphemeralPublic.length !== EPHEMERAL_PUBLIC_BYTES) {
115
+ return {
116
+ ok: false,
117
+ reason: EPHEMERAL_AUTH_REFUSALS.MALFORMED,
118
+ detail: `the peer's session key material is the wrong shape — signature ${opts.peerSignature.length} ` +
119
+ `bytes (expected ${EPHEMERAL_SIG_BYTES}), key ${opts.peerEphemeralPublic?.length ?? 0} bytes ` +
120
+ `(expected ${EPHEMERAL_PUBLIC_BYTES}). Refusing rather than padding: a short value silently ` +
121
+ "zero-extended is an agreement with something that is not the peer.",
122
+ };
123
+ }
124
+ const message = ephemeralSigningMessage(opts.sessionId, opts.peerEphemeralPublic);
125
+ if (!edVerify(opts.expectedIdentityPublic, message, opts.peerSignature)) {
126
+ return {
127
+ ok: false,
128
+ reason: EPHEMERAL_AUTH_REFUSALS.SIGNATURE_MISMATCH,
129
+ detail: "the peer's session key is signed, but not by the counterparty this session is with. That " +
130
+ "is what a relay substituting its own key looks like: it would then share one secret with " +
131
+ "you and another with them, and read everything in between while both sides saw a working " +
132
+ "conversation. Refusing.",
133
+ };
134
+ }
135
+ return { ok: true };
136
+ }
137
+ //# sourceMappingURL=session-ephemeral-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-ephemeral-auth.js","sourceRoot":"","sources":["../src/session-ephemeral-auth.ts"],"names":[],"mappings":"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"}
@@ -54,16 +54,20 @@
54
54
  *
55
55
  * ─── WHAT THIS DOES NOT DEFEND AGAINST, stated plainly (review F6) ─────────────────────────────
56
56
  *
57
- * The ephemerals here are UNAUTHENTICATED. That is sufficient against the threat the DoD line names
58
- * — harvest-now-decrypt-later, i.e. a PASSIVE recorder, which is what a relay storing traffic is.
57
+ * The ephemerals reaching THIS FUNCTION are raw public keys nothing in this API takes an identity
58
+ * key, so it cannot tell whose they are. On its own that is sufficient only against the threat the
59
+ * DoD line names: harvest-now-decrypt-later, i.e. a PASSIVE recorder, which is what a relay storing
60
+ * traffic is. It is NOT sufficient against an ACTIVE on-path relay, which substitutes both
61
+ * ephemerals and reads everything while both ends see a working conversation.
59
62
  *
60
- * It is NOT sufficient against an ACTIVE on-path relay, which can substitute both ephemerals and
61
- * read everything. Nothing in this API takes an identity key, so there is nowhere to bind the
62
- * ephemeral to the peer. `DOD-M15-EPHEMERAL-AUTH-1` carries that: the ephemeral public must be
63
- * signed with the agent's Ed25519 identity and the peer's verified before deriving.
63
+ * THE SYSTEM DOES DEFEND AGAINST THAT NOW `DOD-M15-EPHEMERAL-AUTH-1` shipped it. The ephemeral
64
+ * public is signed with the agent's Ed25519 identity, and `verifySessionEphemeral` checks the peer's
65
+ * against the counterparty identity the SESSION was opened with, BEFORE this function is called. A
66
+ * failure stops the session rather than continuing in the open.
64
67
  *
65
- * Said here because the file's own headline is "CELLO owns its own confidentiality guarantee", and a
66
- * reader could otherwise conclude MITM is covered. It is not, yet.
68
+ * The distinction is kept rather than replaced with "MITM is covered", because it is a property of
69
+ * the CALL ORDER and not of this module: a future caller that derives before verifying has an
70
+ * agreement with whoever sent the bytes, and this file would not notice.
67
71
  *
68
72
  * ─── ONE OUTPUT. The salt used to live here, and that was the defect. ─────────────────────────
69
73
  *
@@ -83,12 +87,49 @@
83
87
  *
84
88
  * ─── The remaining output, and its lifetime ───────────────────────────────────────────────────
85
89
  *
86
- **The envelope key NEVER touches disk** and is destroyed at session close. That is the forward
87
- * secrecy, and `destroySessionEphemeral` is what makes it real. A revived session RE-KEYS (Decisions
88
- * Carried #5) — and because the salt no longer rides on this secret, re-keying no longer disturbs
89
- * the transcript's verifiability. They must never be EQUAL: the salt travels wherever a content hash
90
- * does and the relay sees it, so a salt that equalled the key would hand the key to everyone who can
91
- * see a hash. Domain separation by label is what keeps them independent.
90
+ **The envelope key NEVER touches disk**, and `destroySessionEphemeral` is how a caller discards the
91
+ * secret behind it at session close. A revived session RE-KEYS (Decisions Carried #5) — and because
92
+ * the salt no longer rides on this secret, re-keying no longer disturbs the transcript's
93
+ * verifiability.
94
+ *
95
+ * ⚠️ ALL THREE ARE WIRED NOW, and the history is kept because this file has been wrong in BOTH
96
+ * directions. It first claimed *"that is the forward secrecy, and `destroySessionEphemeral` is what
97
+ * makes it real"* while nothing called it. The correction over-swung to *"nothing in the daemon
98
+ * mints an ephemeral, derives a content key, or destroys one"*, which `006-CRYPTO` made two thirds
99
+ * false the same day. Both were confident; neither was measured.
100
+ *
101
+ * What is true today, and it is checkable in one grep each:
102
+ *
103
+ * `generateSessionEphemeral` / `destroySessionEphemeral` — `session-node-manager.ts` mints one
104
+ * per session at activation and destroys it at every site that drops the session's entry, and at
105
+ * shutdown (`006-CRYPTO`).
106
+ * `deriveSessionSecrets` — called from the same file, on an inbound signed ephemeral, AFTER the
107
+ * peer's signature is verified against the counterparty identity the session was opened with
108
+ * (`007-CRYPTO`). Its output encrypts the message body in `session-content-seal.ts`.
109
+ *
110
+ * ─── WHAT THIS FILE ALONE STILL DOES NOT DEFEND AGAINST ───────────────────────────────────────
111
+ *
112
+ * The ephemerals ARRIVING here are unauthenticated — this module takes raw public keys and cannot
113
+ * tell whose they are. That check is real but it lives one layer up, in
114
+ * `session-ephemeral-auth.ts`, which the daemon runs BEFORE calling this. So the property holds for
115
+ * the system and not for this function: a caller that derives from an unverified peer key has an
116
+ * agreement with whoever sent it, and against an on-path relay that is a relay who can read
117
+ * everything.
118
+ *
119
+ * Said this precisely because `session-salt.ts` states its own reachability boundary and this file
120
+ * once stated none, so the two halves of the same exchange read as though both were live.
121
+ *
122
+ * ─── The key and the salt must never be EQUAL, and what actually keeps them apart ──────────────
123
+ *
124
+ * The salt travels wherever a content hash does and the relay sees it, so a salt that equalled the
125
+ * key would hand the key to everyone who can see a hash.
126
+ *
127
+ * An earlier version said *"domain separation by label is what keeps them independent."* That was
128
+ * true when the salt was a second HKDF output of this function and is not true now. The salt is
129
+ * computed in `session-salt.ts` from a DIFFERENT input — the two sides' random contributions, not
130
+ * this ECDH secret — under its own label, with no HKDF salt. Different inputs, different module,
131
+ * different function. Label separation is not the mechanism; it is not even reachable, because
132
+ * there is only one label here.
92
133
  */
93
134
  export declare const SESSION_KEY_BYTES = 32;
94
135
  export interface SessionEphemeral {
@@ -1 +1 @@
1
- {"version":3,"file":"session-key-agreement.d.ts","sourceRoot":"","sources":["../src/session-key-agreement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2FG;AAQH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAUpC,MAAM,WAAW,gBAAgB;IAC/B,sGAAsG;IACtG,SAAS,EAAE,UAAU,CAAC;IACtB,gEAAgE;IAChE,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,gBAAgB,CAG3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAEjE;AAmBD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,kBAAkB,EAAE,UAAU,CAAC;IAC/B,mBAAmB,EAAE,UAAU,CAAC;IAChC,oEAAoE;IACpE,SAAS,EAAE,UAAU,CAAC;IACtB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,UAAU,CAAC;CAC3B,GAAG,cAAc,CA+IjB"}
1
+ {"version":3,"file":"session-key-agreement.d.ts","sourceRoot":"","sources":["../src/session-key-agreement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoIG;AAQH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAepC,MAAM,WAAW,gBAAgB;IAC/B,sGAAsG;IACtG,SAAS,EAAE,UAAU,CAAC;IACtB,gEAAgE;IAChE,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,gBAAgB,CAG3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAEjE;AAmBD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,kBAAkB,EAAE,UAAU,CAAC;IAC/B,mBAAmB,EAAE,UAAU,CAAC;IAChC,oEAAoE;IACpE,SAAS,EAAE,UAAU,CAAC;IACtB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,UAAU,CAAC;CAC3B,GAAG,cAAc,CAgJjB"}
@@ -54,16 +54,20 @@
54
54
  *
55
55
  * ─── WHAT THIS DOES NOT DEFEND AGAINST, stated plainly (review F6) ─────────────────────────────
56
56
  *
57
- * The ephemerals here are UNAUTHENTICATED. That is sufficient against the threat the DoD line names
58
- * — harvest-now-decrypt-later, i.e. a PASSIVE recorder, which is what a relay storing traffic is.
57
+ * The ephemerals reaching THIS FUNCTION are raw public keys nothing in this API takes an identity
58
+ * key, so it cannot tell whose they are. On its own that is sufficient only against the threat the
59
+ * DoD line names: harvest-now-decrypt-later, i.e. a PASSIVE recorder, which is what a relay storing
60
+ * traffic is. It is NOT sufficient against an ACTIVE on-path relay, which substitutes both
61
+ * ephemerals and reads everything while both ends see a working conversation.
59
62
  *
60
- * It is NOT sufficient against an ACTIVE on-path relay, which can substitute both ephemerals and
61
- * read everything. Nothing in this API takes an identity key, so there is nowhere to bind the
62
- * ephemeral to the peer. `DOD-M15-EPHEMERAL-AUTH-1` carries that: the ephemeral public must be
63
- * signed with the agent's Ed25519 identity and the peer's verified before deriving.
63
+ * THE SYSTEM DOES DEFEND AGAINST THAT NOW `DOD-M15-EPHEMERAL-AUTH-1` shipped it. The ephemeral
64
+ * public is signed with the agent's Ed25519 identity, and `verifySessionEphemeral` checks the peer's
65
+ * against the counterparty identity the SESSION was opened with, BEFORE this function is called. A
66
+ * failure stops the session rather than continuing in the open.
64
67
  *
65
- * Said here because the file's own headline is "CELLO owns its own confidentiality guarantee", and a
66
- * reader could otherwise conclude MITM is covered. It is not, yet.
68
+ * The distinction is kept rather than replaced with "MITM is covered", because it is a property of
69
+ * the CALL ORDER and not of this module: a future caller that derives before verifying has an
70
+ * agreement with whoever sent the bytes, and this file would not notice.
67
71
  *
68
72
  * ─── ONE OUTPUT. The salt used to live here, and that was the defect. ─────────────────────────
69
73
  *
@@ -83,12 +87,49 @@
83
87
  *
84
88
  * ─── The remaining output, and its lifetime ───────────────────────────────────────────────────
85
89
  *
86
- **The envelope key NEVER touches disk** and is destroyed at session close. That is the forward
87
- * secrecy, and `destroySessionEphemeral` is what makes it real. A revived session RE-KEYS (Decisions
88
- * Carried #5) — and because the salt no longer rides on this secret, re-keying no longer disturbs
89
- * the transcript's verifiability. They must never be EQUAL: the salt travels wherever a content hash
90
- * does and the relay sees it, so a salt that equalled the key would hand the key to everyone who can
91
- * see a hash. Domain separation by label is what keeps them independent.
90
+ **The envelope key NEVER touches disk**, and `destroySessionEphemeral` is how a caller discards the
91
+ * secret behind it at session close. A revived session RE-KEYS (Decisions Carried #5) — and because
92
+ * the salt no longer rides on this secret, re-keying no longer disturbs the transcript's
93
+ * verifiability.
94
+ *
95
+ * ⚠️ ALL THREE ARE WIRED NOW, and the history is kept because this file has been wrong in BOTH
96
+ * directions. It first claimed *"that is the forward secrecy, and `destroySessionEphemeral` is what
97
+ * makes it real"* while nothing called it. The correction over-swung to *"nothing in the daemon
98
+ * mints an ephemeral, derives a content key, or destroys one"*, which `006-CRYPTO` made two thirds
99
+ * false the same day. Both were confident; neither was measured.
100
+ *
101
+ * What is true today, and it is checkable in one grep each:
102
+ *
103
+ * `generateSessionEphemeral` / `destroySessionEphemeral` — `session-node-manager.ts` mints one
104
+ * per session at activation and destroys it at every site that drops the session's entry, and at
105
+ * shutdown (`006-CRYPTO`).
106
+ * `deriveSessionSecrets` — called from the same file, on an inbound signed ephemeral, AFTER the
107
+ * peer's signature is verified against the counterparty identity the session was opened with
108
+ * (`007-CRYPTO`). Its output encrypts the message body in `session-content-seal.ts`.
109
+ *
110
+ * ─── WHAT THIS FILE ALONE STILL DOES NOT DEFEND AGAINST ───────────────────────────────────────
111
+ *
112
+ * The ephemerals ARRIVING here are unauthenticated — this module takes raw public keys and cannot
113
+ * tell whose they are. That check is real but it lives one layer up, in
114
+ * `session-ephemeral-auth.ts`, which the daemon runs BEFORE calling this. So the property holds for
115
+ * the system and not for this function: a caller that derives from an unverified peer key has an
116
+ * agreement with whoever sent it, and against an on-path relay that is a relay who can read
117
+ * everything.
118
+ *
119
+ * Said this precisely because `session-salt.ts` states its own reachability boundary and this file
120
+ * once stated none, so the two halves of the same exchange read as though both were live.
121
+ *
122
+ * ─── The key and the salt must never be EQUAL, and what actually keeps them apart ──────────────
123
+ *
124
+ * The salt travels wherever a content hash does and the relay sees it, so a salt that equalled the
125
+ * key would hand the key to everyone who can see a hash.
126
+ *
127
+ * An earlier version said *"domain separation by label is what keeps them independent."* That was
128
+ * true when the salt was a second HKDF output of this function and is not true now. The salt is
129
+ * computed in `session-salt.ts` from a DIFFERENT input — the two sides' random contributions, not
130
+ * this ECDH secret — under its own label, with no HKDF salt. Different inputs, different module,
131
+ * different function. Label separation is not the mechanism; it is not even reachable, because
132
+ * there is only one label here.
92
133
  */
93
134
  import { x25519 } from "@noble/curves/ed25519.js";
94
135
  import { hkdf } from "@noble/hashes/hkdf.js";
@@ -98,9 +139,14 @@ const X25519_KEY_BYTES = 32;
98
139
  export const SESSION_KEY_BYTES = 32;
99
140
  const ENC = new TextEncoder();
100
141
  /**
101
- * Distinct labels are the ONLY thing separating the two outputs same IKM, same salt, same binding.
102
- * Versioned so a future derivation change is a new label rather than a silent reinterpretation of
103
- * the same bytes.
142
+ * THE ONE label. Versioned so a future derivation change is a new label rather than a silent
143
+ * reinterpretation of the same bytes.
144
+ *
145
+ * An earlier version read *"distinct labels are the ONLY thing separating the two outputs — same
146
+ * IKM, same salt, same binding."* There are no longer two outputs to separate: the content-hash
147
+ * salt moved to `session-salt.ts` and is derived from different inputs entirely (Decisions Carried
148
+ * #8). The label still earns its place — it is bound into `info`, so it is what a future second
149
+ * output WOULD be separated by — but it is not currently holding two values apart.
104
150
  */
105
151
  const INFO_CONTENT_KEY = ENC.encode("cello/session/v1/content-key");
106
152
  /**
@@ -150,10 +196,11 @@ export function deriveSessionSecrets(opts) {
150
196
  if (opts.peerEphemeralPublic.length !== X25519_KEY_BYTES) {
151
197
  throw new Error(`KEYAGREE: peer ephemeral public key must be ${X25519_KEY_BYTES} bytes, got ${opts.peerEphemeralPublic.length}. ` +
152
198
  "Refusing rather than padding — a short key silently zero-extended is an agreement with " +
153
- "something that is not the peer. This check ALSO does double duty as the canonicalisation " +
154
- "guard for the HKDF `info` (review F9): the label is recoverable as info[0 : len-64-|transcript|] " +
155
- "only because both public keys are exactly 32 bytes. A variable-length public would let a " +
156
- "crafted key make a content-key info equal a content-salt info.");
199
+ "something that is not the peer. This check ALSO keeps the HKDF `info` unambiguous (review " +
200
+ "F9): with a fixed-length label, two exactly-32-byte public keys and a trailing transcript, " +
201
+ "no two different (keys, transcript) inputs can encode to the same info bytes. A " +
202
+ "variable-length public would break that, and two peers whose info collided would derive the " +
203
+ "same key from different material.");
157
204
  }
158
205
  if (opts.ownEphemeralSecret.length !== X25519_KEY_BYTES) {
159
206
  // Review F11: symmetric with the peer check above. `@noble` catches it, but names its own
@@ -1 +1 @@
1
- {"version":3,"file":"session-key-agreement.js","sourceRoot":"","sources":["../src/session-key-agreement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-key-agreement.js","sourceRoot":"","sources":["../src/session-key-agreement.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cello-protocol/crypto",
3
- "version": "0.0.59",
3
+ "version": "0.0.60",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {