p2party 0.8.0 → 0.14.2

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 (182) hide show
  1. package/LICENSE.md +202 -661
  2. package/README.md +736 -404
  3. package/THIRD_PARTY_NOTICES.md +458 -0
  4. package/docs/assets/p2party-cat.svg +1 -0
  5. package/docs/getting-started.md +203 -0
  6. package/docs/protocol-v4-security.md +158 -0
  7. package/docs/references.md +157 -0
  8. package/docs/session-api.md +457 -0
  9. package/docs/wire-format.md +103 -0
  10. package/examples/standalone-e2ee.ts +194 -0
  11. package/lib/api/signalingServerApi.d.ts +6 -7
  12. package/lib/api/webrtc/baseQuery.d.ts +1 -2
  13. package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts +1 -2
  14. package/lib/api/webrtc/disconnectFromChannelLabelQuery.d.ts +1 -2
  15. package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts +1 -2
  16. package/lib/api/webrtc/disconnectFromPeerQuery.d.ts +3 -3
  17. package/lib/api/webrtc/disconnectFromRoomQuery.d.ts +1 -2
  18. package/lib/api/webrtc/disconnectQuery.d.ts +1 -2
  19. package/lib/api/webrtc/iceGeneration.d.ts +17 -0
  20. package/lib/api/webrtc/iceRepair.d.ts +10 -0
  21. package/lib/api/webrtc/index.d.ts +13 -13
  22. package/lib/api/webrtc/interfaces.d.ts +67 -11
  23. package/lib/api/webrtc/negotiationLock.d.ts +12 -0
  24. package/lib/api/webrtc/openChannelQuery.d.ts +1 -2
  25. package/lib/api/webrtc/pendingIceCandidates.d.ts +14 -0
  26. package/lib/api/webrtc/roomPeer.d.ts +11 -0
  27. package/lib/api/webrtc/sendMessageQuery.d.ts +7 -4
  28. package/lib/api/webrtc/setCandidateQuery.d.ts +1 -2
  29. package/lib/api/webrtc/setDescriptionQuery.d.ts +1 -2
  30. package/lib/cryptography/coverCell.d.ts +65 -0
  31. package/lib/cryptography/cpace.d.ts +41 -0
  32. package/lib/cryptography/ed25519.d.ts +0 -1
  33. package/lib/cryptography/hashStream.d.ts +15 -0
  34. package/lib/cryptography/hkdf.d.ts +3 -0
  35. package/lib/cryptography/identityCrossSig.d.ts +7 -0
  36. package/lib/cryptography/interfaces.d.ts +28 -13
  37. package/lib/cryptography/memory.d.ts +2 -4
  38. package/lib/cryptography/merkle.d.ts +0 -1
  39. package/lib/cryptography/mlkem.d.ts +117 -0
  40. package/lib/cryptography/mnemonic.d.ts +0 -1
  41. package/lib/cryptography/pqHealing.d.ts +268 -0
  42. package/lib/cryptography/pqHealingFrame.d.ts +39 -0
  43. package/lib/cryptography/pqMessageKey.d.ts +30 -0
  44. package/lib/cryptography/random.d.ts +22 -0
  45. package/lib/cryptography/ratchet.d.ts +146 -0
  46. package/lib/cryptography/testModule.d.ts +7 -0
  47. package/lib/cryptography/utils.d.ts +0 -1
  48. package/lib/cryptography/wasmLoader.d.ts +6 -1
  49. package/lib/cryptography/x25519.d.ts +15 -0
  50. package/lib/cryptography/x3dh.d.ts +9 -0
  51. package/lib/db/api.d.ts +54 -22
  52. package/lib/db/db.worker.d.ts +0 -1
  53. package/lib/db/ratchetWrap.d.ts +36 -0
  54. package/lib/db/src/getDB.d.ts +17 -4
  55. package/lib/db/types.d.ts +274 -32
  56. package/lib/db.worker.js +1 -2
  57. package/lib/handlers/chunkFrame.d.ts +13 -0
  58. package/lib/handlers/connectionSignal.d.ts +26 -0
  59. package/lib/handlers/coverEdge.d.ts +42 -0
  60. package/lib/handlers/coverRuntime.d.ts +91 -0
  61. package/lib/handlers/coverScheduler.d.ts +184 -0
  62. package/lib/handlers/coverTransfer.d.ts +46 -0
  63. package/lib/handlers/frameType.d.ts +10 -0
  64. package/lib/handlers/handleChallenge.d.ts +0 -1
  65. package/lib/handlers/handleConnectToPeer.d.ts +0 -1
  66. package/lib/handlers/handleHandshake.d.ts +74 -0
  67. package/lib/handlers/handleMessageQueueing.d.ts +53 -4
  68. package/lib/handlers/handleOpenChannel.d.ts +4 -2
  69. package/lib/handlers/handleQueuedIceCandidates.d.ts +0 -1
  70. package/lib/handlers/handleReadReceipt.d.ts +17 -4
  71. package/lib/handlers/handleReceiveMessage.d.ts +21 -3
  72. package/lib/handlers/handleSendMessage.d.ts +110 -2
  73. package/lib/handlers/handleWebSocketMessage.d.ts +1 -3
  74. package/lib/handlers/handshakeCore.d.ts +95 -0
  75. package/lib/handlers/messageChunkCrypto.d.ts +70 -0
  76. package/lib/handlers/peerRosterDelta.d.ts +12 -0
  77. package/lib/handlers/pqHealingOrchestrator.d.ts +46 -0
  78. package/lib/handlers/pqHealingRuntime.d.ts +82 -0
  79. package/lib/handlers/ratchetGate.d.ts +18 -0
  80. package/lib/handlers/ratchetPersist.d.ts +53 -0
  81. package/lib/handlers/receiptFrame.d.ts +18 -0
  82. package/lib/handlers/receiveMessageKeyLifetime.d.ts +24 -0
  83. package/lib/handlers/reconcile.d.ts +16 -0
  84. package/lib/handlers/transferAbort.d.ts +42 -0
  85. package/lib/index.d.ts +203 -46
  86. package/lib/index.js +1 -2
  87. package/lib/index.min.js +1 -2
  88. package/lib/index.mjs +1 -2
  89. package/lib/libcrypto.provenance.json +45 -0
  90. package/lib/libcrypto.wasm +0 -0
  91. package/lib/middleware/keyPairListenerMiddleware.d.ts +0 -1
  92. package/lib/middleware/roomListenerMiddleware.d.ts +0 -1
  93. package/lib/reducers/commonSlice.d.ts +0 -1
  94. package/lib/reducers/keyPairSlice.d.ts +0 -1
  95. package/lib/reducers/roomSlice.d.ts +65 -3
  96. package/lib/reducers/signalingServerSlice.d.ts +25 -4
  97. package/lib/roomInvite.d.ts +18 -0
  98. package/lib/roomPinAttempts.d.ts +12 -0
  99. package/lib/roomPinVault.d.ts +26 -0
  100. package/lib/roomPolicy.d.ts +60 -0
  101. package/lib/session.d.ts +110 -0
  102. package/lib/session.js +1 -0
  103. package/lib/session.mjs +1 -0
  104. package/lib/store.d.ts +40 -41
  105. package/lib/utils/channelLabel.d.ts +0 -1
  106. package/lib/utils/chunkBounds.d.ts +9 -0
  107. package/lib/utils/constants.d.ts +50 -6
  108. package/lib/utils/debug.d.ts +25 -0
  109. package/lib/utils/drainAndClose.d.ts +5 -0
  110. package/lib/utils/identityRole.d.ts +19 -0
  111. package/lib/utils/interfaces.d.ts +31 -43
  112. package/lib/utils/leafHash.d.ts +13 -0
  113. package/lib/utils/messageTypes.d.ts +0 -1
  114. package/lib/utils/metadata.d.ts +6 -1
  115. package/lib/utils/mutex.d.ts +24 -0
  116. package/lib/utils/protocolVersion.d.ts +5 -0
  117. package/lib/utils/receiptToken.d.ts +7 -0
  118. package/lib/utils/sendQueueKey.d.ts +2 -0
  119. package/lib/utils/signalingAuth.d.ts +8 -0
  120. package/lib/utils/signalingBounds.d.ts +9 -0
  121. package/lib/utils/splitToChunks.d.ts +7 -4
  122. package/lib/utils/uint8array.d.ts +1 -2
  123. package/lib/utils/waitForOpen.d.ts +3 -0
  124. package/lib/utils/zeroFree.d.ts +10 -0
  125. package/package.json +109 -49
  126. package/lib/api/signalingServerApi.d.ts.map +0 -1
  127. package/lib/api/webrtc/baseQuery.d.ts.map +0 -1
  128. package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts.map +0 -1
  129. package/lib/api/webrtc/disconnectFromChannelLabelQuery.d.ts.map +0 -1
  130. package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts.map +0 -1
  131. package/lib/api/webrtc/disconnectFromPeerQuery.d.ts.map +0 -1
  132. package/lib/api/webrtc/disconnectFromRoomQuery.d.ts.map +0 -1
  133. package/lib/api/webrtc/disconnectQuery.d.ts.map +0 -1
  134. package/lib/api/webrtc/index.d.ts.map +0 -1
  135. package/lib/api/webrtc/interfaces.d.ts.map +0 -1
  136. package/lib/api/webrtc/openChannelQuery.d.ts.map +0 -1
  137. package/lib/api/webrtc/sendMessageQuery.d.ts.map +0 -1
  138. package/lib/api/webrtc/setCandidateQuery.d.ts.map +0 -1
  139. package/lib/api/webrtc/setDescriptionQuery.d.ts.map +0 -1
  140. package/lib/cryptography/chacha20poly1305.d.ts +0 -116
  141. package/lib/cryptography/chacha20poly1305.d.ts.map +0 -1
  142. package/lib/cryptography/ed25519.d.ts.map +0 -1
  143. package/lib/cryptography/interfaces.d.ts.map +0 -1
  144. package/lib/cryptography/memory.d.ts.map +0 -1
  145. package/lib/cryptography/merkle.d.ts.map +0 -1
  146. package/lib/cryptography/mnemonic.d.ts.map +0 -1
  147. package/lib/cryptography/utils.d.ts.map +0 -1
  148. package/lib/cryptography/wasmLoader.d.ts.map +0 -1
  149. package/lib/db/api.d.ts.map +0 -1
  150. package/lib/db/db.worker.d.ts.map +0 -1
  151. package/lib/db/src/getDB.d.ts.map +0 -1
  152. package/lib/db/types.d.ts.map +0 -1
  153. package/lib/db.worker.js.map +0 -1
  154. package/lib/handlers/handleChallenge.d.ts.map +0 -1
  155. package/lib/handlers/handleConnectToPeer.d.ts.map +0 -1
  156. package/lib/handlers/handleMessageQueueing.d.ts.map +0 -1
  157. package/lib/handlers/handleOpenChannel.d.ts.map +0 -1
  158. package/lib/handlers/handleQueuedIceCandidates.d.ts.map +0 -1
  159. package/lib/handlers/handleReadReceipt.d.ts.map +0 -1
  160. package/lib/handlers/handleReceiveMessage.d.ts.map +0 -1
  161. package/lib/handlers/handleSendMessage.d.ts.map +0 -1
  162. package/lib/handlers/handleWebSocketMessage.d.ts.map +0 -1
  163. package/lib/index.d.ts.map +0 -1
  164. package/lib/index.js.map +0 -1
  165. package/lib/index.min.js.map +0 -1
  166. package/lib/index.mjs.map +0 -1
  167. package/lib/middleware/keyPairListenerMiddleware.d.ts.map +0 -1
  168. package/lib/middleware/roomListenerMiddleware.d.ts.map +0 -1
  169. package/lib/reducers/commonSlice.d.ts.map +0 -1
  170. package/lib/reducers/keyPairSlice.d.ts.map +0 -1
  171. package/lib/reducers/roomSlice.d.ts.map +0 -1
  172. package/lib/reducers/signalingServerSlice.d.ts.map +0 -1
  173. package/lib/store.d.ts.map +0 -1
  174. package/lib/utils/allocators.d.ts +0 -22
  175. package/lib/utils/allocators.d.ts.map +0 -1
  176. package/lib/utils/channelLabel.d.ts.map +0 -1
  177. package/lib/utils/constants.d.ts.map +0 -1
  178. package/lib/utils/interfaces.d.ts.map +0 -1
  179. package/lib/utils/messageTypes.d.ts.map +0 -1
  180. package/lib/utils/metadata.d.ts.map +0 -1
  181. package/lib/utils/splitToChunks.d.ts.map +0 -1
  182. package/lib/utils/uint8array.d.ts.map +0 -1
@@ -0,0 +1,39 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ import type { MlKemParameterSet, MlKemSuiteDescriptor } from "./mlkem";
3
+ export declare const PQ_CONTROL_FRAME_HEADER_BYTES: number;
4
+ export declare const PQ_CONTROL_FRAME_PLAINTEXT_BYTES: number;
5
+ export type PqControlDirection = "initiator-to-responder" | "responder-to-initiator";
6
+ export type PqControlFrameErrorCode = "authentication-failed" | "binding-mismatch" | "epoch-mismatch" | "invalid-direction" | "invalid-frame" | "invalid-padding" | "record-mismatch";
7
+ export declare class PqControlFrameError extends Error {
8
+ readonly code: PqControlFrameErrorCode;
9
+ constructor(code: PqControlFrameErrorCode, message: string);
10
+ }
11
+ export interface SealPqControlFrameOptions<P extends MlKemParameterSet = MlKemParameterSet> {
12
+ readonly module: LibCrypto;
13
+ readonly suite: Readonly<MlKemSuiteDescriptor<P>>;
14
+ readonly rootKey: Uint8Array;
15
+ readonly binding: Uint8Array;
16
+ readonly direction: PqControlDirection;
17
+ /** Epoch whose PQ root authenticates this frame. */
18
+ readonly keyEpoch: bigint;
19
+ /** Exact canonical OFFER, ADVANCE, or 64-byte ACK. */
20
+ readonly record: Uint8Array;
21
+ }
22
+ export interface OpenPqControlFrameOptions<P extends MlKemParameterSet = MlKemParameterSet> {
23
+ readonly module: LibCrypto;
24
+ readonly suite: Readonly<MlKemSuiteDescriptor<P>>;
25
+ readonly rootKey: Uint8Array;
26
+ readonly binding: Uint8Array;
27
+ /** Expected inbound direction; the opposite direction derives another key. */
28
+ readonly direction: PqControlDirection;
29
+ /** Exact expected authentication epoch. */
30
+ readonly keyEpoch: bigint;
31
+ readonly frame: Uint8Array;
32
+ }
33
+ /** Seal one exact canonical control record into a fixed-size v4 cell. */
34
+ export declare const sealPqControlFrame: <P extends MlKemParameterSet>(options: SealPqControlFrameOptions<P>) => Uint8Array;
35
+ /**
36
+ * Authenticate a fixed-size cell and return an owned exact canonical record.
37
+ * The caller supplies the expected edge, direction, suite, root, and epoch.
38
+ */
39
+ export declare const openPqControlFrame: <P extends MlKemParameterSet>(options: OpenPqControlFrameOptions<P>) => Uint8Array;
@@ -0,0 +1,30 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ import type { RatchetHeader } from "./ratchet";
3
+ import type { RatchetRootSuite } from "../utils/constants";
4
+ /**
5
+ * Context authenticated by the hybrid bootstrap and advanced by sparse PQ
6
+ * healing. `rootKey` is reusable epoch state: this module copies it and never
7
+ * wipes the caller's live buffer.
8
+ */
9
+ export interface PqMessageKeyContext {
10
+ readonly rootKey: Uint8Array;
11
+ readonly binding: Uint8Array;
12
+ readonly rootSuite: RatchetRootSuite;
13
+ readonly epoch: bigint;
14
+ }
15
+ export declare const PQ_MESSAGE_KEY_BYTES: number;
16
+ export declare const PQ_MESSAGE_KEY_ROOT_BYTES = 32;
17
+ export declare const PQ_MESSAGE_KEY_BINDING_BYTES = 32;
18
+ /**
19
+ * Combine one classical Double-Ratchet message key with the current PQ epoch
20
+ * root:
21
+ *
22
+ * PRK = HKDF-Extract-SHA512(salt = pqRoot, IKM = classicalMessageKey)
23
+ * key = HKDF-Expand-SHA512(PRK, canonicalContext, 32)
24
+ *
25
+ * Ownership is deliberate: `classicalMessageKey` is consumed and zeroed on
26
+ * every success/failure path. The live `context.rootKey` remains reusable; only
27
+ * an owned copy and the transient PRK are wiped. Callers that need the
28
+ * classical key for multiple chunks must pass an owned copy on each call.
29
+ */
30
+ export declare const combinePqMessageKey: (classicalMessageKey: Uint8Array, context: PqMessageKeyContext, header: RatchetHeader, module: LibCrypto) => Uint8Array;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Supply Emscripten/libsodium with one Web Crypto backed unsigned word.
3
+ *
4
+ * Passing this callback explicitly keeps the generated glue independent of
5
+ * CommonJS `require("crypto")`, which is unavailable in Node ESM. Browsers,
6
+ * workers, Node 20+, and Bun all expose the same Web Crypto boundary.
7
+ */
8
+ export declare const secureRandomUint32: () => number;
9
+ /**
10
+ * Fill any Uint8Array — including a view into WebAssembly.Memory — without
11
+ * handing its backing buffer to WebCrypto.
12
+ *
13
+ * Chromium 147/149 rejects BufferSource inputs backed by resizable
14
+ * WebAssembly memory. A fresh length-constructed Uint8Array always owns an
15
+ * ordinary fixed ArrayBuffer, so WebCrypto fills that temporary and we copy
16
+ * into the caller's destination. Randomness is secret key material at every
17
+ * current call site; wipe the temporary on success and failure.
18
+ *
19
+ * The optional filler exists for deterministic boundary tests and is not a
20
+ * protocol entropy-injection API.
21
+ */
22
+ export declare const fillRandomBytesInto: (destination: Uint8Array, fill?: (temporary: Uint8Array) => void) => void;
@@ -0,0 +1,146 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ import type { RatchetRootSuite } from "../utils/constants";
3
+ /**
4
+ * Live Double Ratchet state for one `(roomId, peerPublicKey)` edge. Every key
5
+ * field is a plain-JS `Uint8Array` secret (the WASM heap holds no ratchet state
6
+ * — see design §9): `rootKey`, both chain keys, `dhSelfSec`, and each value in
7
+ * `skipped`. Stage 3 wraps these at rest; here they are live plaintext.
8
+ *
9
+ * The ratchet advances **per logical message**, never per chunk. `Ns`/`Nr` are
10
+ * the send/receive message counters in the current chains; `PN` is the length
11
+ * of the previous sending chain (folded into inbound headers so the peer can
12
+ * skip the tail of a superseded chain).
13
+ */
14
+ export interface RatchetState {
15
+ /** Authenticated bootstrap-suite provenance; immutable for this edge. */
16
+ rootSuite: RatchetRootSuite;
17
+ rootKey: Uint8Array;
18
+ sendingChainKey: Uint8Array | null;
19
+ receivingChainKey: Uint8Array | null;
20
+ dhSelfPub: Uint8Array;
21
+ dhSelfSec: Uint8Array;
22
+ dhRemotePub: Uint8Array | null;
23
+ Ns: number;
24
+ Nr: number;
25
+ PN: number;
26
+ skipped: Map<string, Uint8Array>;
27
+ }
28
+ /**
29
+ * Cleartext per-message ratchet header. Rides the frame so the receiver can
30
+ * derive the message key before decrypting: `dhPub` drives the DH ratchet, `N`
31
+ * is this message's index in the sender's current chain, `PN` is the length of
32
+ * the sender's previous chain (for skip-on-DH-step).
33
+ */
34
+ export interface RatchetHeader {
35
+ dhPub: Uint8Array;
36
+ N: number;
37
+ PN: number;
38
+ }
39
+ /**
40
+ * Serializable projection of a `RatchetState` — maps 1:1 onto the wrapped
41
+ * secret fields of the `RatchetSession` IndexedDB row (Stage 3). All buffers
42
+ * are owned copies; the skipped map is flattened to an array keyed by
43
+ * `(dhPub, n)`.
44
+ */
45
+ export interface RatchetSessionSecrets {
46
+ rootSuite: RatchetRootSuite;
47
+ rootKey: ArrayBuffer;
48
+ sendingChainKey: ArrayBuffer | null;
49
+ receivingChainKey: ArrayBuffer | null;
50
+ dhSelfPub: ArrayBuffer;
51
+ dhSelfSec: ArrayBuffer;
52
+ dhRemotePub: ArrayBuffer | null;
53
+ Ns: number;
54
+ Nr: number;
55
+ PN: number;
56
+ skippedMessageKeys: Array<{
57
+ dhPub: ArrayBuffer;
58
+ n: number;
59
+ messageKey: ArrayBuffer;
60
+ }>;
61
+ }
62
+ /**
63
+ * Seed a ratchet from the handshake's 32-byte, transcript-bound hybrid root.
64
+ *
65
+ * Initiator/responder asymmetry (must match so the two sides interoperate):
66
+ * - The **responder** (`amInitiator=false`, `remoteDhPub=null`) generates its
67
+ * DH keypair and stops: both chains stay `null`. After the initiator's
68
+ * initial DH pub is authenticated, `primeResponderRatchet` performs the
69
+ * receive-side DH step without consuming a message key and opens both
70
+ * chains. A lower-level caller that does not prime retains the legacy
71
+ * first-inbound-message behavior.
72
+ * - The **initiator** (`amInitiator=true`) is handed the responder's
73
+ * `dhSelfPub` as `remoteDhPub`, runs one `kdf_rk` over `DH(selfSec, remote)`
74
+ * to advance the root and open its **sending** chain immediately, so it can
75
+ * send message 0 before ever hearing back. Its receiving chain opens on the
76
+ * responder's first reply (a DH step against the responder's fresh pub).
77
+ */
78
+ export declare const initRatchet: (rootSeed: Uint8Array, amInitiator: boolean, remoteDhPub: Uint8Array | null, module: LibCrypto, rootSuite?: RatchetRootSuite) => RatchetState;
79
+ /**
80
+ * Advance the sending chain by one message. Returns the message key (caller's to
81
+ * consume/wipe) and the cleartext header to put on the wire. The consumed chain
82
+ * key is wiped once its successor is derived.
83
+ */
84
+ export declare const ratchetEncrypt: (state: RatchetState, module: LibCrypto) => {
85
+ messageKey: Uint8Array;
86
+ header: RatchetHeader;
87
+ };
88
+ /**
89
+ * Complete the responder's handshake-time ratchet bootstrap after the
90
+ * initiator's initial DH public key has been authenticated by key confirmation.
91
+ *
92
+ * This is the receive-side DH step that an unprimed responder would otherwise
93
+ * perform on the initiator's first message, deliberately stopped before
94
+ * `kdfCk`: it opens the receiving chain from
95
+ * `DH(initialResponder, initialInitiator)`, rotates the responder DH keypair,
96
+ * and opens the sending chain from `DH(rotatedResponder, initialInitiator)`.
97
+ * Consequently both peers can send message 0 immediately after the handshake,
98
+ * including simultaneously, without consuming or skipping a message key.
99
+ */
100
+ export declare const primeResponderRatchet: (state: RatchetState, initiatorDhPub: Uint8Array, module: LibCrypto) => void;
101
+ /**
102
+ * Advance the receiving side for an inbound header and return its message key.
103
+ *
104
+ * CAUTION — this function is UNAUTHENTICATED: it mutates `state` (and may fire
105
+ * a DH-ratchet step) from the cleartext header alone, before the AEAD tag is
106
+ * ever checked (authentication happens later, in Stage 5). A duplicate or
107
+ * replayed message that is NOT a stored skipped key — e.g. a retransmit of a
108
+ * message from a chain the session has since stepped past — is NOT detected
109
+ * here: it falls through to the "new peer DH pub" case below and can fire a
110
+ * spurious backward DH-step, permanently desyncing the session. This is
111
+ * reachable by our own retransmit/reconcile layer, so callers MUST:
112
+ * 1. Dedup already-seen `(header.dhPub, header.N)` pairs BEFORE calling this
113
+ * function — never invoke it a second time for a message already
114
+ * processed.
115
+ * 2. Call `ratchetDecrypt` on a CLONE of `state` (via
116
+ * `deserializeRatchet(serializeRatchet(state))`) and commit that clone as
117
+ * the live state ONLY after the returned message key successfully
118
+ * authenticates the AEAD ciphertext. If authentication fails, discard the
119
+ * clone and leave the live state untouched.
120
+ * `ratchetDecrypt` itself performs neither dedup nor authentication — the safe
121
+ * integration of both rules is wired in Stage 4/5, not here.
122
+ *
123
+ * Against that (untrusted) header, handles three cases: (a) a stored skipped
124
+ * key — out-of-order delivery within an already-seen chain, (b) a new peer DH
125
+ * pub — skip the old chain's tail, then DH-step, (c) a forward message in the
126
+ * current chain — skip any gap, then derive. The consumed chain key is wiped
127
+ * once its successor is derived.
128
+ */
129
+ export declare const ratchetDecrypt: (state: RatchetState, header: RatchetHeader, module: LibCrypto) => Uint8Array;
130
+ /**
131
+ * Snapshot all live state (including the skipped map + DH keys) to owned
132
+ * buffers for at-rest persistence. Does NOT wipe the source state — the caller
133
+ * keeps using it.
134
+ */
135
+ export declare const serializeRatchet: (state: RatchetState) => RatchetSessionSecrets;
136
+ /** Rebuild a live `RatchetState` from a persisted snapshot. */
137
+ export declare const deserializeRatchet: (s: RatchetSessionSecrets) => RatchetState;
138
+ /** Deep-clone a live ratchet state into independently owned key buffers. */
139
+ export declare const cloneRatchet: (state: RatchetState) => RatchetState;
140
+ /** Wipe every secret-bearing buffer owned by a ratchet state. */
141
+ export declare const wipeRatchet: (state: RatchetState) => void;
142
+ /**
143
+ * Replace a live state with an independently owned authenticated successor.
144
+ * The superseded live secrets are wiped before ownership moves from `next`.
145
+ */
146
+ export declare const adoptRatchet: (live: RatchetState, next: RatchetState) => void;
@@ -0,0 +1,7 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ /**
3
+ * Instantiate the locally-built libcrypto.wasm for unit tests, bypassing the
4
+ * CDN + SRI fetch in wasmLoader.ts. 32 pages == 2 MiB == INITIAL_MEMORY; growth
5
+ * is off so every op fits the largest-single-op budget.
6
+ */
7
+ export declare const loadTestModule: () => Promise<LibCrypto>;
@@ -11,4 +11,3 @@ export declare function fisherYatesShuffle<T>(arr: T[]): T[];
11
11
  *
12
12
  * @returns Promise<T[]>
13
13
  */
14
- //# sourceMappingURL=utils.d.ts.map
@@ -1,2 +1,7 @@
1
+ /**
2
+ * Point the browser root at a self-hosted copy of this release's exact WASM.
3
+ * The build-pinned SRI is still enforced. Configure once, before connect() or
4
+ * any other operation first loads cryptography.
5
+ */
6
+ export declare const setWasmSourceUrl: (source: string | URL) => void;
1
7
  export declare const wasmLoader: (wasmMemory: WebAssembly.Memory) => Promise<import("./libcrypto").LibCrypto>;
2
- //# sourceMappingURL=wasmLoader.d.ts.map
@@ -0,0 +1,15 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ export interface X25519KeyPair {
3
+ publicKey: Uint8Array;
4
+ secretKey: Uint8Array;
5
+ }
6
+ export declare const x25519Keypair: (module: LibCrypto) => X25519KeyPair;
7
+ /**
8
+ * Async, optional-module wrapper over `x25519Keypair`, mirroring `ed25519.newKeyPair`:
9
+ * self-loads a LibCrypto module (sizing its own fixed 2 MiB heap) when none is passed,
10
+ * so identity-generation call sites can mint the dedicated X25519 identity keypair the
11
+ * same way they call `newKeyPair()`. The keypair is random (`_x25519_keypair` draws its
12
+ * own entropy); `x25519Keypair` copies the secret out and zero-frees the wasm scratch.
13
+ */
14
+ export declare const newX25519KeyPair: (module?: LibCrypto) => Promise<X25519KeyPair>;
15
+ export declare const x25519Dh: (secretKey: Uint8Array, publicKey: Uint8Array, module: LibCrypto) => Uint8Array;
@@ -0,0 +1,9 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ /**
3
+ * No-PIN identity-mixed ephemeral DH. Mixes
4
+ * DH(IK_a, EK_b) || DH(EK_a, IK_b) || DH(EK_a, EK_b)
5
+ * (initiator orientation) then HKDF-SHA512 to a 32-byte root seed. The responder
6
+ * passes amInitiator=false; the three DH calls are re-ordered so both sides
7
+ * concatenate the identical shared values.
8
+ */
9
+ export declare const deriveInteractive3dhSecret: (idSelfSec: Uint8Array, idPeerPub: Uint8Array, ephSelfSec: Uint8Array, ephPeerPub: Uint8Array, amInitiator: boolean, module: LibCrypto) => Uint8Array;
package/lib/db/api.d.ts CHANGED
@@ -1,35 +1,67 @@
1
- import type { Chunk, NewChunk, SendQueue } from "./types";
1
+ import type { Chunk, ReceiveChunk, NewChunk, NewChunkSelector, SendQueue, RatchetSession, IdentityEd25519, IdentityX25519 } from "./types";
2
2
  export declare const getDBAddressBookEntry: (peerId?: string, peerPublicKey?: string) => Promise<import("./types").UsernamedPeer | undefined>;
3
3
  export declare const getAllDBAddressBookEntries: () => Promise<import("./types").UsernamedPeer[]>;
4
- export declare const setDBAddressBookEntry: (username: string, peerId: string, peerPublicKey: string) => Promise<void>;
4
+ export declare const setDBAddressBookEntry: (username: string, peerId: string, peerPublicKey: string) => Promise<undefined>;
5
5
  export declare const deleteDBAddressBookEntry: (username?: string, peerId?: string, peerPublicKey?: string) => Promise<string>;
6
+ /**
7
+ * Fails CLOSED. This is the sole admission gate on every connection path, and
8
+ * an indeterminate answer must never be reported as "not blacklisted" — that
9
+ * would let a storage fault silently readmit every blocked peer. The denial is
10
+ * scoped to the one peer being checked, so a transient fault cannot lock the
11
+ * whole room out.
12
+ */
6
13
  export declare const getDBPeerIsBlacklisted: (peerId?: string, peerPublicKey?: string) => Promise<boolean>;
7
14
  export declare const getAllDBBlacklisted: () => Promise<import("./types").BlacklistedPeer[]>;
8
- export declare const setDBPeerInBlacklist: (peerId: string, peerPublicKey: string) => Promise<void>;
9
- export declare const deleteDBPeerFromBlacklist: (peerId?: string, peerPublicKey?: string) => Promise<void>;
15
+ export declare const setDBPeerInBlacklist: (peerId: string, peerPublicKey: string) => Promise<undefined>;
16
+ export declare const deleteDBPeerFromBlacklist: (peerId?: string, peerPublicKey?: string) => Promise<undefined>;
10
17
  export declare const getAllDBUniqueRooms: () => Promise<import("./types").UniqueRoom[]>;
11
- export declare const setDBUniqueRoom: (roomUrl: string, roomId: string) => Promise<void>;
18
+ export declare const setDBUniqueRoom: (roomUrl: string, roomId: string, roomPolicy: ArrayBuffer) => Promise<undefined>;
12
19
  export declare const getDBMessageData: (merkleRootHex?: string, hashHex?: string) => Promise<import("./types").MessageData | undefined>;
13
20
  export declare const getDBRoomMessageData: (roomId: string) => Promise<import("./types").MessageData[]>;
21
+ export declare const getDBRoomStats: (roomId: string) => Promise<import("./types").RoomStats>;
14
22
  export declare const setDBRoomMessageData: (roomId: string, merkleRootHex: string, sha512Hex: string, fromPeerId: string, chunkSize: number, totalSize: number, messageType: number, // MessageType,
15
- filename: string, channelLabel: string, timestamp: number) => Promise<void>;
16
- export declare const getDBChunk: (hashHex: string, chunkIndex: number) => Promise<ArrayBuffer | undefined>;
17
- export declare const existsDBChunk: (hashHex: string, chunkIndex: number) => Promise<boolean>;
18
- export declare const getDBNewChunk: (hashHex: string, chunkIndex?: number) => Promise<NewChunk | undefined>;
19
- export declare const existsDBNewChunk: (hashHex: string, chunkIndex: number) => Promise<boolean>;
23
+ filename: string, channelLabel: string, timestamp: number, transferId?: string) => Promise<undefined>;
24
+ export declare const getDBChunk: (merkleRootHex: string, chunkIndex: number) => Promise<ArrayBuffer | undefined>;
25
+ export declare const existsDBChunk: (merkleRootHex: string, chunkIndex: number) => Promise<boolean>;
26
+ export declare const getDBNewChunk: (transferId: string, chunkIndex: number) => Promise<NewChunk | undefined>;
27
+ export declare const getDBNewChunkByReceipt: (merkleRootHex: string, receiptTokenHex: string) => Promise<NewChunk | undefined>;
28
+ export declare const existsDBNewChunk: (transferId: string, chunkIndex: number) => Promise<boolean>;
20
29
  export declare const getDBSendQueue: (label: string, toPeerId: string) => Promise<SendQueue[]>;
21
30
  export declare const getDBAllChunks: (merkleRootHex?: string, hashHex?: string) => Promise<Chunk[]>;
31
+ export declare const getDBAllChunkLeafHashes: (merkleRootHex: string) => Promise<import("./types").ChunkLeafHash[]>;
32
+ export declare const assembleToOPFS: (merkleRootHex: string, totalSize: number, filename: string, mimeType: string) => Promise<File | null>;
22
33
  export declare const getDBAllChunksCount: (merkleRootHex?: string, hashHex?: string) => Promise<number>;
23
- export declare const setDBChunk: (chunk: Chunk) => Promise<void>;
24
- export declare const getDBAllNewChunks: (hashHex?: string, merkleRootHex?: string) => Promise<NewChunk[]>;
25
- export declare const getDBAllNewChunksCount: (hashHex: string) => Promise<number>;
26
- export declare const setDBNewChunk: (chunk: NewChunk) => Promise<void>;
27
- export declare const setDBSendQueue: (item: SendQueue) => Promise<void>;
34
+ export declare const setDBChunk: (chunk: Chunk) => Promise<undefined>;
35
+ export declare const storeReceiveChunk: (chunk: ReceiveChunk) => Promise<import("./types").ReceiveChunkStoreResult>;
36
+ export declare const getReceiveFile: (merkleRootHex: string, totalSize: number, filename: string, mimeType: string) => Promise<File | null>;
37
+ export declare const closeReceiveFile: (merkleRootHex: string) => Promise<undefined>;
38
+ /**
39
+ * Atomically retires one inbound transfer behind the same per-Merkle worker
40
+ * lock used by storeReceiveChunk. This is the cancellation primitive: a chunk
41
+ * write that was already in flight completes first and is then removed, while
42
+ * later writes are stopped by the channel's AbortSignal.
43
+ */
44
+ export declare const deleteReceiveTransfer: (merkleRootHex: string) => Promise<undefined>;
45
+ export declare const getDBAllNewChunks: (selector: NewChunkSelector) => Promise<NewChunk[]>;
46
+ export declare const getDBAllNewChunksCount: (transferId: string) => Promise<number>;
47
+ export declare const setDBNewChunk: (chunk: NewChunk) => Promise<undefined>;
48
+ export declare const setDBSendQueue: (item: SendQueue) => Promise<undefined>;
28
49
  export declare const countDBSendQueue: (label: string, toPeerId: string) => Promise<number>;
29
- export declare const deleteDBChunk: (hashHex: string, chunkIndex?: number) => Promise<void>;
30
- export declare const deleteDBNewChunk: (merkleRootHex?: string, realChunkHashHex?: string, hashHex?: string, chunkIndex?: number) => Promise<void>;
31
- export declare const deleteDBMessageData: (merkleRootHex: string) => Promise<void>;
32
- export declare const deleteDBUniqueRoom: (roomId: string) => Promise<void>;
33
- export declare const deleteDB: () => Promise<void>;
34
- export declare const deleteDBSendQueue: (label: string, toPeerId: string, position?: number) => Promise<void>;
35
- //# sourceMappingURL=api.d.ts.map
50
+ export declare const deleteDBChunk: (hashHex: string, chunkIndex?: number) => Promise<undefined>;
51
+ export declare const deleteDBNewChunk: (selector: NewChunkSelector) => Promise<undefined>;
52
+ export declare const deleteDBMessageData: (merkleRootHex: string) => Promise<undefined>;
53
+ export declare const deleteDBUniqueRoom: (roomId: string) => Promise<undefined>;
54
+ export declare const deleteDB: () => Promise<undefined>;
55
+ export declare const deleteDBSendQueue: (label: string, toPeerId: string, position?: number) => Promise<undefined>;
56
+ export declare const getRatchetSession: (roomId: string, peerPublicKey: string) => Promise<RatchetSession | undefined>;
57
+ export declare const setRatchetSession: (session: RatchetSession) => Promise<undefined>;
58
+ export declare const deleteRatchetSession: (roomId: string, peerPublicKey: string) => Promise<undefined>;
59
+ export declare const getPinAttemptState: (roomId: string, peerIdentityEd25519: string) => Promise<import("./types").PinAttemptState | undefined>;
60
+ export declare const incrementPinAttemptState: (roomId: string, peerIdentityEd25519: string, now: number, maxImmediateAttempts: number, baseMs: number, maxMs: number) => Promise<import("./types").PinAttemptState>;
61
+ export declare const deletePinAttemptState: (roomId: string, peerIdentityEd25519?: string) => Promise<undefined>;
62
+ export declare const getIdentityX25519: () => Promise<IdentityX25519 | undefined>;
63
+ export declare const setIdentityX25519: (identity: IdentityX25519) => Promise<undefined>;
64
+ export declare const deleteIdentityX25519: () => Promise<undefined>;
65
+ export declare const getIdentityEd25519: () => Promise<IdentityEd25519 | undefined>;
66
+ export declare const setIdentityEd25519: (identity: IdentityEd25519) => Promise<undefined>;
67
+ export declare const deleteIdentityEd25519: () => Promise<undefined>;
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=db.worker.d.ts.map
@@ -0,0 +1,36 @@
1
+ import type { RatchetSession } from "./types";
2
+ export declare const RATCHET_WRAP_VERSION = 2;
3
+ /** Bounded canonical v4 PQ/outbox/active-key checkpoint (plaintext bytes). */
4
+ export declare const MAX_EDGE_CRYPTO_STATE_BYTES: number;
5
+ /**
6
+ * Best-effort rollback/equivocation detection for one running client context.
7
+ *
8
+ * Callers pass an instance to `unwrapRatchetSession`; a successfully
9
+ * authenticated record may advance `updatedAt`, but may not move backwards or
10
+ * present different ciphertext at the same timestamp. `forget` is required
11
+ * when an edge is intentionally deleted/re-established.
12
+ *
13
+ * This cannot detect replay of an older *complete* IndexedDB snapshot after a
14
+ * full browser restart: WebCrypto/IndexedDB expose no trusted monotonic
15
+ * counter. Durable cross-restart detection needs an independently protected
16
+ * high-water head (or a remote/trusted anchor), atomically advanced with the
17
+ * ratchet row. AES-GCM alone cannot provide that property.
18
+ */
19
+ export declare class RatchetRollbackGuard {
20
+ #private;
21
+ acceptAuthenticated(s: RatchetSession): Promise<void>;
22
+ /**
23
+ * Advance the in-process high-water mark after, and only after, a local
24
+ * wrapped row was durably stored. The record's canonical metadata and every
25
+ * envelope shape/record ID are validated, but the locally produced
26
+ * ciphertext is intentionally not decrypted.
27
+ */
28
+ rememberTrustedWrite(wrapped: RatchetSession): Promise<void>;
29
+ forget(roomId: string, peerPublicKey: string): void;
30
+ clear(): void;
31
+ }
32
+ export declare function getWrapKey(): Promise<CryptoKey>;
33
+ export declare function wrapSecret(key: CryptoKey, bytes: ArrayBuffer): Promise<ArrayBuffer>;
34
+ export declare function unwrapSecret(key: CryptoKey, blob: ArrayBuffer): Promise<ArrayBuffer>;
35
+ export declare function wrapRatchetSession(s: RatchetSession, key: CryptoKey): Promise<RatchetSession>;
36
+ export declare function unwrapRatchetSession(s: RatchetSession, key: CryptoKey, rollbackGuard?: RatchetRollbackGuard): Promise<RatchetSession>;
@@ -1,7 +1,7 @@
1
1
  import type { DBSchema, IDBPDatabase } from "idb";
2
- import type { MessageData, Chunk, SendQueue, AddressBook, BlacklistedPeer, UniqueRoom, NewChunk } from "../types";
2
+ import type { MessageData, Chunk, SendQueue, AddressBook, BlacklistedPeer, UniqueRoom, NewChunk, RatchetSession, StoredIdentityX25519, StoredIdentityEd25519, PinAttemptState } from "../types";
3
3
  export declare const dbName = "p2party";
4
- export declare const dbVersion = 16;
4
+ export declare const dbVersion = 19;
5
5
  export interface RepoSchema extends DBSchema {
6
6
  addressBook: {
7
7
  value: AddressBook;
@@ -51,9 +51,10 @@ export interface RepoSchema extends DBSchema {
51
51
  value: NewChunk;
52
52
  key: [string, number];
53
53
  indexes: {
54
+ transferId: string;
54
55
  hash: string;
55
56
  merkleRoot: string;
56
- realChunkHash: string;
57
+ receiptScope: [string, string];
57
58
  };
58
59
  };
59
60
  sendQueue: {
@@ -63,6 +64,18 @@ export interface RepoSchema extends DBSchema {
63
64
  labelPeer: string;
64
65
  };
65
66
  };
67
+ ratchetSessions: {
68
+ value: RatchetSession;
69
+ key: [string, string];
70
+ indexes: {
71
+ peerId: string;
72
+ peerPublicKey: string;
73
+ roomId: string;
74
+ };
75
+ };
76
+ meta: {
77
+ value: CryptoKey | StoredIdentityX25519 | StoredIdentityEd25519 | PinAttemptState;
78
+ key: string;
79
+ };
66
80
  }
67
81
  export declare function getDB(): Promise<IDBPDatabase<RepoSchema>>;
68
- //# sourceMappingURL=getDB.d.ts.map