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,203 @@
1
+ # Getting started with p2party 0.14
2
+
3
+ p2party has two entry points:
4
+
5
+ - `p2party` owns the browser room mesh: signaling, WebRTC, Redux state,
6
+ IndexedDB, OPFS when available, the protocol-v4 handshake, and message
7
+ transfer.
8
+ - `p2party/session` owns only the protocol-v4 handshake and message
9
+ cryptography. Use it with Node, Bun, a native shell, tests, or your own
10
+ transport and storage.
11
+
12
+ Install is in the [README](../README.md#install). This guide assumes you have
13
+ the package and picks up from there.
14
+
15
+ ## Browser room mesh
16
+
17
+ The root entry point requires a browser with WebRTC, WebAssembly, WebCrypto,
18
+ Worker, and IndexedDB. OPFS is optional; the receive path falls back to
19
+ IndexedDB when it is unavailable.
20
+
21
+ ```ts
22
+ import p2party from "p2party";
23
+
24
+ const invite = p2party.generateRoomInvite();
25
+ const room = await p2party.joinRoom(invite);
26
+
27
+ console.log("joined room", room.id);
28
+ ```
29
+
30
+ `joinRoom()` is `connect()` plus a wait for the signaling service to assign the
31
+ room its id. Use the two separately when you want to render a joining state, or
32
+ when you need a deadline or cancellation:
33
+
34
+ ```ts
35
+ await p2party.connect(invite);
36
+ const room = await p2party.waitForRoom(invite, {
37
+ timeoutMs: 10_000,
38
+ signal: controller.signal,
39
+ });
40
+ ```
41
+
42
+ Every peer that joins the same room is connected to every other present peer.
43
+ The signaling service coordinates discovery and WebRTC setup; it is not the
44
+ message hub. A room with `n` participants therefore has up to `n(n - 1) / 2`
45
+ peer edges.
46
+
47
+ `connect()` resolving does not by itself mean that every peer edge has
48
+ completed protocol-v4 authentication. The library gates message cryptography on
49
+ the authenticated handshake. A UI should render peer and message state from
50
+ the exported store rather than treating `connect()` as a global room-ready
51
+ event.
52
+
53
+ ## Compact, fragment, and word invites
54
+
55
+ Generate one capability and derive every presentation from the same bytes:
56
+
57
+ ```ts
58
+ const capability = p2party.generateRoomCapability();
59
+
60
+ const compact = p2party.encodeRoomCapabilityBase64Url(capability); // 43 chars
61
+ const fragment = p2party.encodeRoomInviteFragment(capability); // v1.<compact>
62
+ const words = await p2party.encodeRoomCapabilityWords(capability); // 24 words
63
+
64
+ const fromCompact = p2party.decodeRoomCapabilityBase64Url(compact);
65
+ const fromFragment = p2party.decodeRoomInviteFragment(`#${fragment}`);
66
+ const fromWords = await p2party.decodeRoomCapabilityWords(words);
67
+
68
+ await p2party.connect(fragment);
69
+ ```
70
+
71
+ `generateRoomInvite()` is the one-line form when only the versioned fragment is
72
+ needed. Put it after `#` in an HTTPS URL so ordinary HTTP requests do not carry
73
+ the capability. The current `legacy-signaling` connection path still sends a
74
+ normalized form to the signaling service, so this is not server-blind
75
+ rendezvous.
76
+
77
+ The word form is a checksum-protected encoding of the same 256-bit capability,
78
+ not a lower-entropy replacement. Its fixed word-list identifier is exported as
79
+ `ROOM_INVITE_WORDLIST_ID`.
80
+
81
+ ## PIN room with an exact ML-KEM suite
82
+
83
+ Room policy is immutable after local room creation. Every peer must use the
84
+ same policy and the same PIN bytes. The suite is fixed before the handshake;
85
+ there is no in-band negotiation, downgrade, or classical fallback.
86
+
87
+ ```ts
88
+ import p2party, { type RoomPolicyV1 } from "p2party";
89
+
90
+ const invite = p2party.generateRoomInvite();
91
+ const policy = {
92
+ ...p2party.DEFAULT_ROOM_POLICY_V1,
93
+ authMode: "pin",
94
+ pqMode: "hybrid-mlkem1024",
95
+ } satisfies RoomPolicyV1;
96
+ const pin = new TextEncoder().encode("replace with a room secret");
97
+
98
+ try {
99
+ await p2party.connect(invite, undefined, undefined, { policy, pin });
100
+ } finally {
101
+ // connect() copied it into the in-memory room vault.
102
+ pin.fill(0);
103
+ }
104
+ ```
105
+
106
+ The exact supported `pqMode` values are `hybrid-mlkem512`,
107
+ `hybrid-mlkem768`, and `hybrid-mlkem1024`; ML-KEM-768 is the default. PIN
108
+ bytes are deliberately absent from the public policy, Redux, persistent room
109
+ records, and logs. PIN mode adds CPace authentication to the identity and
110
+ ML-KEM handshake; it does not replace identity possession.
111
+
112
+ Scheduled timing cover is wired as of 0.14: a policy may pin `coverMode:
113
+ "scheduled"` with a cadence, lane count, and frames per cell, and every edge in
114
+ the room then emits fixed-size cells on that schedule whether or not data is
115
+ queued. Private rendezvous modes are still rejected by `connect()` because
116
+ their live transport wiring is not complete.
117
+
118
+ ## Send, cancel, and read
119
+
120
+ Wait until the room has peers before sending. Each logical send has a random
121
+ transfer ID and opens a per-message data channel on every eligible peer edge.
122
+
123
+ ```ts
124
+ const handle = p2party.sendMessage("hello room", "chat", room.id);
125
+
126
+ console.log("transfer", handle.transferId);
127
+
128
+ // Wire this to a cancel button. It also works during hashing/channel setup.
129
+ const cancel = () => handle.cancel();
130
+
131
+ try {
132
+ const result = await handle.done;
133
+ console.table(result?.outcomes);
134
+
135
+ const opened = await p2party.readMessage(result!.merkleRootHex);
136
+ console.log(opened.message, opened.percentage);
137
+ } catch (error) {
138
+ // `done` REJECTS when no peer took delivery — an empty room, or a cancel.
139
+ // Both are ordinary outcomes, not bugs. The error carries the same per-peer
140
+ // detail a resolved value would have.
141
+ if (error instanceof p2party.MessageDeliveryError)
142
+ console.table(error.result.outcomes);
143
+ }
144
+
145
+ void cancel; // Remove when a UI event uses it.
146
+ ```
147
+
148
+ `sendMessage()` returns a `MessageTransferHandle`, not a promise. `done`
149
+ settles after all started peer sends and cleanup and reports ordered per-peer
150
+ outcomes. A peer may be delivered, failed during setup/transfer, or skipped
151
+ because it is disconnected, unauthenticated, or the transfer was cancelled.
152
+
153
+ For an inbound message, take `merkleRootHex` (and, if needed, `sha512Hex`) from
154
+ the room's exported `messages` state:
155
+
156
+ ```ts
157
+ const rooms = p2party.roomSelector(p2party.store.getState());
158
+ const message = rooms
159
+ .find((candidate) => candidate.id === room.id)
160
+ ?.messages.at(-1);
161
+
162
+ if (message) {
163
+ const metadataOnly = await p2party.readMessage(
164
+ message.merkleRootHex,
165
+ message.sha512Hex,
166
+ false,
167
+ );
168
+ console.log(metadataOnly.filename, metadataOnly.size);
169
+ }
170
+ ```
171
+
172
+ `materialize = false` avoids assembling a completed file Blob; text is always
173
+ returned. The application limit is 10 GiB. Cancellation is scoped most
174
+ precisely by the handle's transfer ID, so prefer `handle.cancel()` over a
175
+ content-hash lookup for concurrent identical sends.
176
+
177
+ ## Package artifacts and WASM
178
+
179
+ The 0.14 package exports:
180
+
181
+ - `p2party` — browser ESM/CJS root with declarations;
182
+ - `p2party/session` — store-free ESM/CJS session API with declarations;
183
+ - `p2party/libcrypto.wasm` — the exact compiled cryptographic module;
184
+ - `p2party/libcrypto.provenance.json` — source/toolchain/digest provenance;
185
+ - `p2party/docs/getting-started.md`, `p2party/docs/session-api.md`, and
186
+ `p2party/docs/protocol-v4-security.md` — installed developer and threat-model
187
+ documentation;
188
+ - `p2party/examples/standalone-e2ee.ts` — a runnable source-checkout and
189
+ installed-package session example;
190
+ - `p2party/THIRD_PARTY_NOTICES.md`; and
191
+ - `p2party/package.json`.
192
+
193
+ The tarball also contains the UMD browser build and generated database worker.
194
+ The root bundle embeds the worker source; normal package consumers do not
195
+ construct its URL.
196
+
197
+ The browser root fetches the exact versioned CDN WASM under a build-pinned
198
+ SHA-384 Subresource Integrity value. JavaScript and WASM are one release unit —
199
+ never pair 0.14 JavaScript with an older WASM.
200
+
201
+ Self-hosting those bytes, and passing them directly to `p2party/session`, are
202
+ both covered in the
203
+ [README](../README.md#local-self-hosted-or-release-pinned-wasm).
@@ -0,0 +1,158 @@
1
+ # Protocol-v4 security boundary
2
+
3
+ This document states what p2party 0.14's code path does, what observers still
4
+ learn, and which adjacent mechanisms are not production properties. It is a
5
+ developer threat-model summary, not an independent audit or a formal proof.
6
+
7
+ Protocol v4 is a clean wire break. Missing, malformed, older, and mismatched
8
+ wire versions fail closed; there is no legacy cryptographic fallback.
9
+
10
+ ## What establishes a peer edge
11
+
12
+ There are three different acknowledgements in the system:
13
+
14
+ 1. An `RTCDataChannel` becoming `open` means the DTLS/SCTP transport and that
15
+ channel are ready. An in-band channel may have completed its DCEP OPEN/ACK,
16
+ but this is not p2party identity or key confirmation.
17
+ 2. The protocol-v4 handshake runs over the open main channel. After HELLO,
18
+ responder CONFIRM, initiator CONFIRM, and responder FINISH, the peers have
19
+ authenticated the same hybrid root and initial ratchet keys.
20
+ 3. Authenticated 65-byte receipt frames acknowledge message chunks and final
21
+ transfer completion. They are delivery/reconciliation signals, not handshake
22
+ establishment.
23
+
24
+ An open data channel therefore is necessary transport readiness, not an
25
+ established p2party crypto session.
26
+
27
+ The handshake combines:
28
+
29
+ - interactive 3DH proving possession of fresh ephemeral X25519 keys and
30
+ dedicated long-term X25519 identity keys;
31
+ - Ed25519-pinned identities cross-signing those X25519 identity keys with a
32
+ domain-separated transcript;
33
+ - one room-fixed ML-KEM-512, ML-KEM-768, or ML-KEM-1024 shared secret;
34
+ - draft-21 CPace in PIN rooms; and
35
+ - HKDF/HMAC transcript binding and three chained key-confirmation flights.
36
+
37
+ The authenticated channel input binds the channel identifier, initiator and
38
+ responder Ed25519 identities, ordered endpoint fingerprints, and exact ML-KEM
39
+ suite tag. The room policy is fixed before traffic; a suite/mode mismatch
40
+ poisons the transcript instead of negotiating or falling back.
41
+
42
+ The initiator returns established only after receiving and verifying FINISH.
43
+ The responder returns after successfully sending FINISH. Losing that final
44
+ flight can leave the responder complete while the initiator waits and
45
+ eventually fails. That is an availability/common-knowledge limit of the final
46
+ message, not evidence that an attacker learned the root key.
47
+
48
+ ## Post-handshake message protection
49
+
50
+ Every authenticated peer edge owns independent Double Ratchet state. Either
51
+ role may send first, and simultaneous first sends are tested. Each logical
52
+ message consumes one message-key step; its chunks share the authenticated
53
+ ratchet header and use fresh nonces. Failed authentication rolls back the
54
+ candidate receive state, and skipped-key storage is bounded.
55
+
56
+ Each chunk frame is exactly 65,490 bytes:
57
+
58
+ ```text
59
+ type(1) || DH public key(32) || N(8) || PN(8) || PQ epoch(8) ||
60
+ nonce(12) || encrypted fixed plaintext cell(65,405) || AEAD tag(16)
61
+ ```
62
+
63
+ The 69-byte clear header is authenticated as AAD, excluding the fresh random
64
+ nonce. The PQ epoch is an unsigned 64-bit counter — widened from v3's single
65
+ byte so the sparse post-quantum healing epoch cannot wrap.
66
+
67
+ The fixed frame geometry absorbs the ratchet and AEAD overhead into the cell
68
+ budget. Random padding and decoy slots can hide the exact payload length within
69
+ one transfer's chosen number of frames. Receipts have a distinct fixed 65-byte
70
+ geometry. Handshake flights are suite- and step-dependent rather than
71
+ 65,490-byte cells.
72
+
73
+ Per-message channels give each transfer an independent lifecycle for
74
+ cancellation, bounded channel accounting, receipts, selective retransmission,
75
+ and reconnect resume. Channel isolation is a UX and reliability property; it
76
+ does not make timing or channel count invisible.
77
+
78
+ ## Guarantees, assuming authenticated peer keys
79
+
80
+ With a correctly pinned peer Ed25519 identity, uncompromised endpoints, matching
81
+ room configuration, and successful confirmation, the implementation is
82
+ designed to provide:
83
+
84
+ - mutual possession authentication for the cross-signed X25519 identities;
85
+ - optional shared-PIN authentication in addition to identity authentication;
86
+ - a hybrid initial root dependent on both classical 3DH and the selected
87
+ ML-KEM exchange;
88
+ - transcript binding to roles, identities, endpoint fingerprints, policy
89
+ suite, KEM fields, and initial ratchet public keys;
90
+ - confidentiality and integrity for message cells;
91
+ - forward evolution and post-compromise recovery from later uncompromised
92
+ classical DH ratchet turns;
93
+ - replay/tamper rejection within the ratchet and transfer protocols; and
94
+ - bounded out-of-order key retention and bounded per-edge transfer resources.
95
+
96
+ These are implementation claims, not a claim of equivalence to Signal's PQXDH
97
+ proofs or to a standardized X-Wing combiner. p2party's handshake is interactive,
98
+ includes transport and optional CPace binding, and uses its own explicitly
99
+ domain-separated combiner. The code has not completed an independent
100
+ third-party cryptographic audit or a ProVerif/CryptoVerif analysis.
101
+
102
+ ## Observable metadata
103
+
104
+ Encryption does not hide all communication metadata.
105
+
106
+ The current legacy signaling operator can observe:
107
+
108
+ - the normalized room capability and room membership;
109
+ - peer identifiers and presented public identity keys;
110
+ - signaling timing, SDP, ICE candidates, IP/network information, and TURN use;
111
+ - room joins, leaves, and connection attempts; and
112
+ - any fallback/relay metadata explicitly sent through server-controlled paths.
113
+
114
+ A network observer can still estimate connection timing, endpoints where
115
+ WebRTC exposes them, packet volume, transfer duration, and traffic bursts. An
116
+ endpoint peer necessarily learns plaintexts it decrypts, peer identity, message
117
+ ordering, and transfer activity.
118
+
119
+ Fixed chunk cells hide exact plaintext length only within the frame-count
120
+ bucket and chosen decoy allocation. With immediate delivery, observers still
121
+ see when a message starts, how many cells/channels are active, when receipts
122
+ flow, and when a transfer ends. Fixed cells without a room-wide schedule are
123
+ not continuous cover traffic.
124
+
125
+ Putting the capability in a URL fragment keeps it out of ordinary HTTP
126
+ requests and common access logs, but the shipped legacy signaling path still
127
+ receives its normalized value. A fragment is not a server-blind meeting point.
128
+
129
+ ## Shipped, implemented core, and research
130
+
131
+ | Status | Exact boundary in 0.14 |
132
+ | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
133
+ | Shipped public path | Full WebRTC room mesh; protocol-v4 hybrid 3DH + exact room-fixed ML-KEM-512/768/1024 bootstrap; optional CPace PIN rooms; chained triple confirmation; per-edge Double Ratchet; fixed message cells and in-transfer decoys; per-message channels; authenticated receipts, cancellation, selective retransmission, reconnect resume; compact/fragment/word invites; store-free `createSession()`/`restoreSession()` API. |
134
+ | Shipped, newer | Sparse post-quantum healing (OFFER/ADVANCE/ACK epoch exchange) with persist-before-dispatch and application traffic blocked while an epoch is in flight. Room-wide scheduled timing cover: policy-pinned cadence, lanes, and frames per cell, emitted whether or not data is queued. |
135
+ | Research/design direction | Opaque/server-blind rendezvous and blind meeting points; a private BitTorrent-compatible swarm extension; multi-device/group-state designs beyond independent pairwise mesh edges; and machine-checked formal analysis comparable in scope to PQXDH work. |
136
+
137
+ Scheduled cover is a room-wide property: it hides _when_ a peer has something
138
+ to say only for as long as every edge in the room keeps emitting on the
139
+ schedule. It does not hide room membership from the signaling operator, and it
140
+ does not apply to rooms whose policy selects immediate delivery.
141
+
142
+ ## Deployment obligations
143
+
144
+ Applications using `p2party/session` own several security-critical jobs:
145
+
146
+ - authenticate or explicitly TOFU-pin peer Ed25519 keys;
147
+ - bind the session to a real transport context and route handshake frames
148
+ without cross-session confusion;
149
+ - keep long-term Ed25519/X25519 secrets in protected storage;
150
+ - encrypt snapshots at rest and enforce rollback protection;
151
+ - wipe caller-owned PIN, identity-secret, WASM scratch, and snapshot buffers
152
+ when their lifecycle ends;
153
+ - enforce timeouts, message-size/resource limits, and abuse controls; and
154
+ - update JavaScript and its exact release-matched WASM together.
155
+
156
+ For browser-mesh setup and artifact behavior, see
157
+ [Getting started](getting-started.md). For the standalone transport and
158
+ snapshot contract, see [Store-free session API](session-api.md).
@@ -0,0 +1,157 @@
1
+ # References
2
+
3
+ What p2party is built from, and what it is built on. Every entry links to a
4
+ primary source: a standard, a paper, or the implementation itself.
5
+
6
+ For the full research treatment — including a per-claim novelty assessment and
7
+ 142 verified citations — see
8
+ [Related work and prior art](paper-prior-art-and-related-work.md).
9
+
10
+ ## 1. Cryptographic dependencies
11
+
12
+ These are compiled into the shipped `libcrypto.wasm` or bundled into the
13
+ package. Licences and notices are reproduced in
14
+ [THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md).
15
+
16
+ | Project | Used for | Link |
17
+ | ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
18
+ | libsodium | X25519, Ed25519, ChaCha20-Poly1305, BLAKE2b, HKDF, Argon2, SHA-512 | [github.com/jedisct1/libsodium](https://github.com/jedisct1/libsodium) |
19
+ | mlkem-native | ML-KEM-512/768/1024 (FIPS 203) | [github.com/pq-code-package/mlkem-native](https://github.com/pq-code-package/mlkem-native) |
20
+ | Emscripten | Compiles the C cryptography to the pinned WASM module | [emscripten.org](https://emscripten.org/) |
21
+ | BIP-39 English wordlist | The 24-word room-capability encoding | [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md) |
22
+ | Redux Toolkit | Browser-root state store | [redux-toolkit.js.org](https://redux-toolkit.js.org/) |
23
+
24
+ ## 2. Standards the wire format implements
25
+
26
+ | Standard | Where it appears in p2party | Link |
27
+ | ------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
28
+ | **FIPS 203** — ML-KEM | Room-fixed post-quantum bootstrap and healing epochs | [csrc.nist.gov/pubs/fips/203/final](https://csrc.nist.gov/pubs/fips/203/final) |
29
+ | **RFC 8439** — ChaCha20-Poly1305 | AEAD for every chunk frame | [rfc-editor.org/rfc/rfc8439](https://www.rfc-editor.org/rfc/rfc8439.html) |
30
+ | **RFC 5869** — HKDF | Root and chain-key derivation | [rfc-editor.org/rfc/rfc5869](https://www.rfc-editor.org/rfc/rfc5869.html) |
31
+ | **RFC 7748** — X25519 | Interactive 3DH and the ratchet DH turns | [rfc-editor.org/rfc/rfc7748](https://www.rfc-editor.org/rfc/rfc7748.html) |
32
+ | **RFC 8032** — Ed25519 | Long-term identity keys and cross-signatures | [rfc-editor.org/rfc/rfc8032](https://www.rfc-editor.org/rfc/rfc8032.html) |
33
+ | **draft-irtf-cfrg-cpace-21** — CPace | PIN-room balanced PAKE | [datatracker.ietf.org](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-cpace-21) |
34
+ | **RFC 8831 / 8832** — WebRTC data channels | The transport every peer edge runs over | [8831](https://datatracker.ietf.org/doc/html/rfc8831) · [8832](https://datatracker.ietf.org/doc/html/rfc8832) |
35
+ | **RFC 8122** — SDP DTLS fingerprints | Endpoint fingerprints bound into the handshake transcript | [datatracker.ietf.org](https://datatracker.ietf.org/doc/html/rfc8122) |
36
+ | **RFC 9794** — PQ/T hybrid terminology | How the hybrid security boundary is described | [rfc-editor.org/rfc/rfc9794](https://www.rfc-editor.org/rfc/rfc9794.html) |
37
+
38
+ ## 3. Papers the design follows
39
+
40
+ **Ratcheting and the Signal lineage**
41
+
42
+ - M. Marlinspike, T. Perrin. _The Double Ratchet Algorithm._ Signal, 2016.
43
+ https://signal.org/docs/specifications/doubleratchet/
44
+ - M. Marlinspike, T. Perrin. _The X3DH Key Agreement Protocol._ Signal, 2016.
45
+ https://signal.org/docs/specifications/x3dh/
46
+ - J. Alwen, S. Coretti, Y. Dodis. _The Double Ratchet: Security Notions,
47
+ Proofs, and Modularization for the Signal Protocol._ EUROCRYPT 2019.
48
+ https://eprint.iacr.org/2018/1037
49
+ - K. Cohn-Gordon, C. Cremers, B. Dowling, L. Garratt, D. Stebila. _A Formal
50
+ Security Analysis of the Signal Messaging Protocol._ EuroS&P 2017; J.
51
+ Cryptology 33(4), 2020. https://eprint.iacr.org/2016/1013
52
+
53
+ **Post-quantum messaging**
54
+
55
+ - E. Kret, R. Schmidt. _The PQXDH Key Agreement Protocol._ Signal, 2023.
56
+ https://signal.org/docs/specifications/pqxdh/
57
+ - K. Bhargavan, C. Jacomme, F. Kiefer, R. Schmidt. _Formal Verification of the
58
+ PQXDH Post-Quantum Key Agreement Protocol._ USENIX Security 2024.
59
+ https://www.usenix.org/system/files/usenixsecurity24-bhargavan.pdf
60
+ - Y. Dodis, D. Jost, S. Katsumata, T. Prest, R. Schmidt. _The Triple Ratchet: A
61
+ Bandwidth Efficient Hybrid-Secure Signal Protocol._ EUROCRYPT 2025.
62
+ https://eprint.iacr.org/2025/078
63
+ - B. Auerbach, Y. Dodis, D. Jost, S. Katsumata, T. Prest, R. Schmidt.
64
+ _Post-Quantum Ratcheting for Signal._ NIST 6th PQC Standardization
65
+ Conference, 2025.
66
+ https://csrc.nist.gov/csrc/media/events/2025/sixth-pqc-standardization-conference/post-quantum%20ratcheting%20for%20signal.pdf
67
+ - M. Barbosa et al. _X-Wing: The Hybrid KEM You've Been Looking For._ IACR
68
+ Communications in Cryptology, 2024. https://eprint.iacr.org/2024/039
69
+ - F. Linker, R. Sasse, D. Basin. _A Formal Analysis of Apple's iMessage PQ3
70
+ Protocol._ USENIX Security 2025.
71
+ https://www.usenix.org/conference/usenixsecurity25/presentation/linker
72
+
73
+ p2party's sparse post-quantum healing is directly inspired by Signal's SPQR
74
+ design; the two are not the same construction, and p2party's has not been
75
+ independently analysed.
76
+
77
+ - Signal Foundation. _SPQR: Signal Protocol and Post-Quantum Ratchets._ 2025.
78
+ https://signal.org/blog/spqr/ ·
79
+ https://github.com/signalapp/SparsePostQuantumRatchet
80
+
81
+ **PAKE and channel binding**
82
+
83
+ - M. Abdalla, B. Haase, J. Hesse. _Security Analysis of CPace._ ASIACRYPT 2021.
84
+ https://eprint.iacr.org/2021/114
85
+ - N. Williams. _RFC 5056: On the Use of Channel Bindings to Secure Channels._
86
+ https://www.rfc-editor.org/rfc/rfc5056.html
87
+
88
+ **Traffic analysis and cover traffic** — the basis for scheduled cover, and for
89
+ the honest limits stated in the
90
+ [security boundary](protocol-v4-security.md).
91
+
92
+ - A. Piotrowska, J. Hayes, T. Elahi, S. Meiser, G. Danezis. _The Loopix
93
+ Anonymity System._ USENIX Security 2017. https://arxiv.org/abs/1703.00536
94
+ - X. Cai, R. Nithyanand, T. Wang, R. Johnson, I. Goldberg. _A Systematic
95
+ Approach to Developing and Evaluating Website Fingerprinting Defenses
96
+ (Tamaraw)._ ACM CCS 2014. https://doi.org/10.1145/2660267.2660362
97
+ - T. Pulls, E. Witwer. _Maybenot: A Framework for Traffic Analysis Defenses._
98
+ WPES @ CCS 2023. https://doi.org/10.1145/3603216.3624953
99
+ - S. Sasy, I. Goldberg. _SoK: Metadata-Protecting Communication Systems._
100
+ PoPETs 2024. https://doi.org/10.56553/popets-2024-0030
101
+ - M. Weisenseel, C. Döpmann, F. Tschorsch. _The Last Hop Attack: Why Loop Cover
102
+ Traffic over Fixed Cascades Threatens Anonymity._ PoPETs 2025.
103
+ https://doi.org/10.56553/popets-2025-0067
104
+ - K. Nikitin et al. _Reducing Metadata Leakage from Encrypted Files and
105
+ Communication with PURBs._ PoPETs 2019.
106
+ https://petsymposium.org/popets/2019/popets-2019-0056.php
107
+
108
+ ## 4. Related open-source systems
109
+
110
+ Projects solving adjacent problems. Several informed p2party's design; none
111
+ share its code.
112
+
113
+ **Browser E2E ratchets**
114
+
115
+ - [matrix-org/vodozemac](https://github.com/matrix-org/vodozemac) — Rust/WASM
116
+ Olm and Megolm for Matrix.
117
+ - [wireapp/core-crypto](https://github.com/wireapp/core-crypto) — MLS and
118
+ Proteus for Wire, compiled to WASM.
119
+ - [PeculiarVentures/2key-ratchet](https://github.com/PeculiarVentures/2key-ratchet)
120
+ — Double Ratchet + X3DH on WebCrypto (archived).
121
+ - [PeculiarVentures/pqc-ratchet](https://github.com/PeculiarVentures/pqc-ratchet)
122
+ — post-quantum Double Ratchet, ML-KEM-768 + X25519.
123
+ - [LukaJCB/ts-mls](https://github.com/LukaJCB/ts-mls) — TypeScript MLS
124
+ (RFC 9420) with post-quantum ciphersuites.
125
+
126
+ **Browser peer-to-peer transfer**
127
+
128
+ - [saljam/webwormhole](https://github.com/saljam/webwormhole) — CPace over
129
+ WebRTC with DTLS-fingerprint binding; the closest prior art to p2party's PIN
130
+ rooms.
131
+ - [magic-wormhole](https://github.com/magic-wormhole/magic-wormhole-protocols) —
132
+ SPAKE2 code-phrase transfer; origin of the short-code UX.
133
+ - [schlagmichdoch/PairDrop](https://github.com/schlagmichdoch/PairDrop) and
134
+ [kern/filepizza](https://github.com/kern/filepizza) — WebRTC file transfer
135
+ without accounts.
136
+ - [js-libp2p](https://libp2p.io/docs/webrtc-browser-connectivity/) — WebRTC
137
+ browser transport with Noise.
138
+
139
+ **Traffic shaping and obfuscation**
140
+
141
+ - [Yawning/obfs4](https://github.com/Yawning/obfs4/blob/master/doc/obfs4-spec.txt)
142
+ — padding and timing obfuscation for Tor pluggable transports.
143
+ - [maybenot](https://github.com/maybenot-io/maybenot) — the framework behind
144
+ the traffic-analysis defence paper above.
145
+
146
+ ## 5. How to cite p2party
147
+
148
+ p2party has not been published as a paper and has not completed an independent
149
+ third-party security audit. Cite the implementation:
150
+
151
+ ```bibtex
152
+ @software{p2party,
153
+ title = {p2party: protocol-v4 end-to-end encryption over a WebRTC room mesh},
154
+ url = {https://github.com/p2party/p2party-js},
155
+ note = {Version 0.14.2}
156
+ }
157
+ ```