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.
- package/LICENSE.md +202 -661
- package/README.md +736 -404
- package/THIRD_PARTY_NOTICES.md +458 -0
- package/docs/assets/p2party-cat.svg +1 -0
- package/docs/getting-started.md +203 -0
- package/docs/protocol-v4-security.md +158 -0
- package/docs/references.md +157 -0
- package/docs/session-api.md +457 -0
- package/docs/wire-format.md +103 -0
- package/examples/standalone-e2ee.ts +194 -0
- package/lib/api/signalingServerApi.d.ts +6 -7
- package/lib/api/webrtc/baseQuery.d.ts +1 -2
- package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts +1 -2
- package/lib/api/webrtc/disconnectFromChannelLabelQuery.d.ts +1 -2
- package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts +1 -2
- package/lib/api/webrtc/disconnectFromPeerQuery.d.ts +3 -3
- package/lib/api/webrtc/disconnectFromRoomQuery.d.ts +1 -2
- package/lib/api/webrtc/disconnectQuery.d.ts +1 -2
- package/lib/api/webrtc/iceGeneration.d.ts +17 -0
- package/lib/api/webrtc/iceRepair.d.ts +10 -0
- package/lib/api/webrtc/index.d.ts +13 -13
- package/lib/api/webrtc/interfaces.d.ts +67 -11
- package/lib/api/webrtc/negotiationLock.d.ts +12 -0
- package/lib/api/webrtc/openChannelQuery.d.ts +1 -2
- package/lib/api/webrtc/pendingIceCandidates.d.ts +14 -0
- package/lib/api/webrtc/roomPeer.d.ts +11 -0
- package/lib/api/webrtc/sendMessageQuery.d.ts +7 -4
- package/lib/api/webrtc/setCandidateQuery.d.ts +1 -2
- package/lib/api/webrtc/setDescriptionQuery.d.ts +1 -2
- package/lib/cryptography/coverCell.d.ts +65 -0
- package/lib/cryptography/cpace.d.ts +41 -0
- package/lib/cryptography/ed25519.d.ts +0 -1
- package/lib/cryptography/hashStream.d.ts +15 -0
- package/lib/cryptography/hkdf.d.ts +3 -0
- package/lib/cryptography/identityCrossSig.d.ts +7 -0
- package/lib/cryptography/interfaces.d.ts +28 -13
- package/lib/cryptography/memory.d.ts +2 -4
- package/lib/cryptography/merkle.d.ts +0 -1
- package/lib/cryptography/mlkem.d.ts +117 -0
- package/lib/cryptography/mnemonic.d.ts +0 -1
- package/lib/cryptography/pqHealing.d.ts +268 -0
- package/lib/cryptography/pqHealingFrame.d.ts +39 -0
- package/lib/cryptography/pqMessageKey.d.ts +30 -0
- package/lib/cryptography/random.d.ts +22 -0
- package/lib/cryptography/ratchet.d.ts +146 -0
- package/lib/cryptography/testModule.d.ts +7 -0
- package/lib/cryptography/utils.d.ts +0 -1
- package/lib/cryptography/wasmLoader.d.ts +6 -1
- package/lib/cryptography/x25519.d.ts +15 -0
- package/lib/cryptography/x3dh.d.ts +9 -0
- package/lib/db/api.d.ts +54 -22
- package/lib/db/db.worker.d.ts +0 -1
- package/lib/db/ratchetWrap.d.ts +36 -0
- package/lib/db/src/getDB.d.ts +17 -4
- package/lib/db/types.d.ts +274 -32
- package/lib/db.worker.js +1 -2
- package/lib/handlers/chunkFrame.d.ts +13 -0
- package/lib/handlers/connectionSignal.d.ts +26 -0
- package/lib/handlers/coverEdge.d.ts +42 -0
- package/lib/handlers/coverRuntime.d.ts +91 -0
- package/lib/handlers/coverScheduler.d.ts +184 -0
- package/lib/handlers/coverTransfer.d.ts +46 -0
- package/lib/handlers/frameType.d.ts +10 -0
- package/lib/handlers/handleChallenge.d.ts +0 -1
- package/lib/handlers/handleConnectToPeer.d.ts +0 -1
- package/lib/handlers/handleHandshake.d.ts +74 -0
- package/lib/handlers/handleMessageQueueing.d.ts +53 -4
- package/lib/handlers/handleOpenChannel.d.ts +4 -2
- package/lib/handlers/handleQueuedIceCandidates.d.ts +0 -1
- package/lib/handlers/handleReadReceipt.d.ts +17 -4
- package/lib/handlers/handleReceiveMessage.d.ts +21 -3
- package/lib/handlers/handleSendMessage.d.ts +110 -2
- package/lib/handlers/handleWebSocketMessage.d.ts +1 -3
- package/lib/handlers/handshakeCore.d.ts +95 -0
- package/lib/handlers/messageChunkCrypto.d.ts +70 -0
- package/lib/handlers/peerRosterDelta.d.ts +12 -0
- package/lib/handlers/pqHealingOrchestrator.d.ts +46 -0
- package/lib/handlers/pqHealingRuntime.d.ts +82 -0
- package/lib/handlers/ratchetGate.d.ts +18 -0
- package/lib/handlers/ratchetPersist.d.ts +53 -0
- package/lib/handlers/receiptFrame.d.ts +18 -0
- package/lib/handlers/receiveMessageKeyLifetime.d.ts +24 -0
- package/lib/handlers/reconcile.d.ts +16 -0
- package/lib/handlers/transferAbort.d.ts +42 -0
- package/lib/index.d.ts +203 -46
- package/lib/index.js +1 -2
- package/lib/index.min.js +1 -2
- package/lib/index.mjs +1 -2
- package/lib/libcrypto.provenance.json +45 -0
- package/lib/libcrypto.wasm +0 -0
- package/lib/middleware/keyPairListenerMiddleware.d.ts +0 -1
- package/lib/middleware/roomListenerMiddleware.d.ts +0 -1
- package/lib/reducers/commonSlice.d.ts +0 -1
- package/lib/reducers/keyPairSlice.d.ts +0 -1
- package/lib/reducers/roomSlice.d.ts +65 -3
- package/lib/reducers/signalingServerSlice.d.ts +25 -4
- package/lib/roomInvite.d.ts +18 -0
- package/lib/roomPinAttempts.d.ts +12 -0
- package/lib/roomPinVault.d.ts +26 -0
- package/lib/roomPolicy.d.ts +60 -0
- package/lib/session.d.ts +110 -0
- package/lib/session.js +1 -0
- package/lib/session.mjs +1 -0
- package/lib/store.d.ts +40 -41
- package/lib/utils/channelLabel.d.ts +0 -1
- package/lib/utils/chunkBounds.d.ts +9 -0
- package/lib/utils/constants.d.ts +50 -6
- package/lib/utils/debug.d.ts +25 -0
- package/lib/utils/drainAndClose.d.ts +5 -0
- package/lib/utils/identityRole.d.ts +19 -0
- package/lib/utils/interfaces.d.ts +31 -43
- package/lib/utils/leafHash.d.ts +13 -0
- package/lib/utils/messageTypes.d.ts +0 -1
- package/lib/utils/metadata.d.ts +6 -1
- package/lib/utils/mutex.d.ts +24 -0
- package/lib/utils/protocolVersion.d.ts +5 -0
- package/lib/utils/receiptToken.d.ts +7 -0
- package/lib/utils/sendQueueKey.d.ts +2 -0
- package/lib/utils/signalingAuth.d.ts +8 -0
- package/lib/utils/signalingBounds.d.ts +9 -0
- package/lib/utils/splitToChunks.d.ts +7 -4
- package/lib/utils/uint8array.d.ts +1 -2
- package/lib/utils/waitForOpen.d.ts +3 -0
- package/lib/utils/zeroFree.d.ts +10 -0
- package/package.json +109 -49
- package/lib/api/signalingServerApi.d.ts.map +0 -1
- package/lib/api/webrtc/baseQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectFromChannelLabelQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectFromPeerQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectFromRoomQuery.d.ts.map +0 -1
- package/lib/api/webrtc/disconnectQuery.d.ts.map +0 -1
- package/lib/api/webrtc/index.d.ts.map +0 -1
- package/lib/api/webrtc/interfaces.d.ts.map +0 -1
- package/lib/api/webrtc/openChannelQuery.d.ts.map +0 -1
- package/lib/api/webrtc/sendMessageQuery.d.ts.map +0 -1
- package/lib/api/webrtc/setCandidateQuery.d.ts.map +0 -1
- package/lib/api/webrtc/setDescriptionQuery.d.ts.map +0 -1
- package/lib/cryptography/chacha20poly1305.d.ts +0 -116
- package/lib/cryptography/chacha20poly1305.d.ts.map +0 -1
- package/lib/cryptography/ed25519.d.ts.map +0 -1
- package/lib/cryptography/interfaces.d.ts.map +0 -1
- package/lib/cryptography/memory.d.ts.map +0 -1
- package/lib/cryptography/merkle.d.ts.map +0 -1
- package/lib/cryptography/mnemonic.d.ts.map +0 -1
- package/lib/cryptography/utils.d.ts.map +0 -1
- package/lib/cryptography/wasmLoader.d.ts.map +0 -1
- package/lib/db/api.d.ts.map +0 -1
- package/lib/db/db.worker.d.ts.map +0 -1
- package/lib/db/src/getDB.d.ts.map +0 -1
- package/lib/db/types.d.ts.map +0 -1
- package/lib/db.worker.js.map +0 -1
- package/lib/handlers/handleChallenge.d.ts.map +0 -1
- package/lib/handlers/handleConnectToPeer.d.ts.map +0 -1
- package/lib/handlers/handleMessageQueueing.d.ts.map +0 -1
- package/lib/handlers/handleOpenChannel.d.ts.map +0 -1
- package/lib/handlers/handleQueuedIceCandidates.d.ts.map +0 -1
- package/lib/handlers/handleReadReceipt.d.ts.map +0 -1
- package/lib/handlers/handleReceiveMessage.d.ts.map +0 -1
- package/lib/handlers/handleSendMessage.d.ts.map +0 -1
- package/lib/handlers/handleWebSocketMessage.d.ts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/index.min.js.map +0 -1
- package/lib/index.mjs.map +0 -1
- package/lib/middleware/keyPairListenerMiddleware.d.ts.map +0 -1
- package/lib/middleware/roomListenerMiddleware.d.ts.map +0 -1
- package/lib/reducers/commonSlice.d.ts.map +0 -1
- package/lib/reducers/keyPairSlice.d.ts.map +0 -1
- package/lib/reducers/roomSlice.d.ts.map +0 -1
- package/lib/reducers/signalingServerSlice.d.ts.map +0 -1
- package/lib/store.d.ts.map +0 -1
- package/lib/utils/allocators.d.ts +0 -22
- package/lib/utils/allocators.d.ts.map +0 -1
- package/lib/utils/channelLabel.d.ts.map +0 -1
- package/lib/utils/constants.d.ts.map +0 -1
- package/lib/utils/interfaces.d.ts.map +0 -1
- package/lib/utils/messageTypes.d.ts.map +0 -1
- package/lib/utils/metadata.d.ts.map +0 -1
- package/lib/utils/splitToChunks.d.ts.map +0 -1
- 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
|
+
```
|