Rename the entire workspace:
- Crate packages: quicnprotochat-{core,proto,server,client,gui,p2p,mobile} -> quicproquo-*
- Binary names: quicnprotochat -> qpq, quicnprotochat-server -> qpq-server,
quicnprotochat-gui -> qpq-gui
- Default files: *-state.bin -> qpq-state.bin, *-server.toml -> qpq-server.toml,
*.db -> qpq.db
- Environment variable prefix: QUICNPROTOCHAT_* -> QPQ_*
- App identifier: chat.quicnproto.gui -> chat.quicproquo.gui
- Proto package: quicnprotochat.bench -> quicproquo.bench
- All documentation, Docker, CI, and script references updated
HKDF domain-separation strings and P2P ALPN remain unchanged for
backward compatibility with existing encrypted state and wire protocol.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.8 KiB
Architecture Overview
quicproquo is an end-to-end encrypted group messaging system built in Rust. This page describes the high-level architecture: the services that compose the system, the dual-key cryptographic model, and how the pieces fit together.
Two-Service Model
The server exposes two logical services through a single NodeService RPC interface, bound to port 7000 over QUIC + TLS 1.3:
| Logical Service | Responsibility |
|---|---|
| Authentication Service (AS) | Stores and distributes single-use MLS KeyPackages. Clients upload KeyPackages after identity generation; peers fetch them to add new members to a group. |
| Delivery Service (DS) | Store-and-forward relay for opaque payloads. The DS never inspects MLS ciphertext -- it routes solely by recipient Ed25519 public key (and optional channel ID). |
Combining both services into a single endpoint simplifies deployment and
reduces round-trips. The schema is defined in
schemas/node.capnp as a unified
NodeService interface.
See Service Architecture for per-method details,
connection lifecycle, and the long-polling fetchWait mechanism.
Identity Key Model
Each quicproquo client holds a single Ed25519 signing keypair that serves as its long-term identity:
quicproquo Key Model
┌──────────────────────────────────────────────────┐
│ │
│ Ed25519 signing keypair (MLS identity) │
│ ────────────────────────────────────── │
│ - Generated once per user/device │
│ - Embedded in MLS BasicCredential │
│ - Signs KeyPackages, Commits, and group ops │
│ - Raw 32-byte public key is the AS index │
│ - Managed by IdentityKeypair, zeroize-on-drop │
│ │
└──────────────────────────────────────────────────┘
| Property | Ed25519 (MLS) |
|---|---|
| Curve | Ed25519 (Twisted Edwards) |
| Purpose | Identity binding, signing, MLS credentials |
| Crate | ed25519-dalek |
| Zeroize on drop | Yes (Zeroizing<[u8; 32]>) |
| PQ protection | MLS key schedule uses DHKEM(X25519); hybrid PQ KEM available at envelope level |
For details on the cryptographic properties, see Ed25519 Identity Keys.
System Diagram
┌─────────────────┐ ┌─────────────────┐
│ Alice Client │ │ Bob Client │
│ │ │ │
│ IdentityKeypair │ │ IdentityKeypair │
│ (Ed25519) │ │ (Ed25519) │
│ │ │ │
│ GroupMember │ │ GroupMember │
│ (MLS state) │ │ (MLS state) │
└────────┬─────────┘ └────────┬─────────┘
│ │
│ QUIC + TLS 1.3 (quinn/rustls) │
│ │
▼ ▼
┌────────────────────────────────────────────────────────────────────────────┐
│ NodeService (port 7000) │
│ │
│ ┌──────────────────────────┐ ┌───────────────────────────────────┐ │
│ │ Authentication Service │ │ Delivery Service │ │
│ │ │ │ │ │
│ │ uploadKeyPackage() │ │ enqueue(recipientKey, payload) │ │
│ │ fetchKeyPackage() │ │ fetch(recipientKey) │ │
│ │ uploadHybridKey() │ │ fetchWait(recipientKey, timeout) │ │
│ │ fetchHybridKey() │ │ │ │
│ │ │ │ Queues: DashMap + FileBackedStore│ │
│ │ Store: DashMap + │ │ │ │
│ │ FileBackedStore │ │ │ │
│ └──────────────────────────┘ └───────────────────────────────────┘ │
│ │
│ health() │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Key observations:
-
The server never sees plaintext message content. MLS ciphertext is opaque to the DS -- it merely routes by
recipientKey. -
KeyPackages are single-use (RFC 9420 requirement). The AS atomically removes a KeyPackage on fetch to enforce this invariant.
-
QUIC + TLS 1.3 is the sole transport layer.
Protocol Layering
The system stacks three protocol layers:
-
Transport -- QUIC + TLS 1.3. Provides confidentiality, integrity, and server authentication. See Protocol Stack.
-
Framing / RPC -- Cap'n Proto serialisation and RPC. Provides zero-copy typed messages, schema versioning, and async method dispatch. See Cap'n Proto Serialisation and RPC.
-
End-to-End Encryption -- MLS (RFC 9420). Provides group key agreement, forward secrecy, and post-compromise security. The server never holds group keys. See MLS (RFC 9420).
An optional fourth layer -- the hybrid KEM envelope (X25519 + ML-KEM-768) -- wraps MLS payloads for post-quantum confidentiality at the per-message level. See Hybrid KEM.
Crate Map
The implementation is split across four workspace crates:
| Crate | Role |
|---|---|
quicproquo-core |
Crypto primitives, MLS state machine, hybrid KEM |
quicproquo-proto |
Cap'n Proto schemas, codegen, and serialisation helpers |
quicproquo-server |
QUIC listener, NodeService RPC, storage |
quicproquo-client |
QUIC client, CLI subcommands, state persistence |
See Crate Responsibilities for a full breakdown and dependency diagram.
Further Reading
- Protocol Stack -- layered protocol stack description
- Service Architecture -- NodeService RPC methods, connection lifecycle, long-polling
- End-to-End Data Flow -- registration, group creation, and message exchange sequence diagrams
- Wire Format Overview -- Cap'n Proto schema reference
- Cryptography Overview -- detailed cryptographic properties and threat model