Files
quicproquo/docs/src/architecture/overview.md
Christian Nennemann 2e081ead8e chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
Rename all project references from quicproquo/qpq to quicprochat/qpc
across documentation, Docker configuration, CI workflows, packaging
scripts, operational configs, and build tooling.

- Docker: crate paths, binary names, user/group, data dirs, env vars
- CI: workflow crate references, binary names, artifact names
- Docs: all markdown files under docs/, SDK READMEs, book.toml
- Packaging: OpenWrt Makefile, init script, UCI config (file renames)
- Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team
- Operations: Prometheus config, alert rules, Grafana dashboard
- Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths
- Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
2026-03-21 19:14:06 +01:00

8.6 KiB

Architecture Overview

quicprochat 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 unified RPC endpoint bound to port 5001 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. Also manages hybrid PQ public keys and identity resolution.
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).

Both services are accessed through a single QUIC connection using the v2 Protobuf framing protocol. Each RPC call gets a dedicated QUIC bidirectional stream to prevent head-of-line blocking.

See Service Architecture for per-method details, connection lifecycle, and push event delivery.


Identity Key Model

Each quicprochat client holds a single Ed25519 signing keypair that serves as its long-term identity:

                    quicprochat 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 X25519+ML-KEM-768 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)       |
  |                  |                                      |                  |
  |  QpqClient       |                                      |  QpqClient       |
  |  (SDK)           |                                      |  (SDK)           |
  +--------+---------+                                      +--------+---------+
           |                                                         |
           |  QUIC + TLS 1.3  (quinn/rustls)  ALPN: "qpc"           |
           |                                                         |
           v                                                         v
  +------------------------------------------------------------------------+
  |              quicprochat-server  (port 5001)                            |
  |                                                                        |
  |  +---------------------------+   +--------------------------------+    |
  |  |  Authentication Service   |   |       Delivery Service         |    |
  |  |                           |   |                                |    |
  |  |  OpaqueRegisterStart(100) |   |  Enqueue(200)                  |    |
  |  |  OpaqueRegisterFinish(101)|   |  Fetch(201)                    |    |
  |  |  OpaqueLoginStart(102)    |   |  FetchWait(202)                |    |
  |  |  OpaqueLoginFinish(103)   |   |  Peek(203)                     |    |
  |  |                           |   |  Ack(204)                      |    |
  |  |  UploadKeyPackage(300)    |   |  BatchEnqueue(205)             |    |
  |  |  FetchKeyPackage(301)     |   |                                |    |
  |  |  UploadHybridKey(302)     |   |  Store: SQLCipher              |    |
  |  |  FetchHybridKey(303)      |   |  DashMap waiters               |    |
  |  |  FetchHybridKeys(304)     |   +--------------------------------+    |
  |  +---------------------------+                                         |
  |                                                                        |
  |  + 34 more methods: Keys, Channel, Group, User, KT, Blob, Device,    |
  |    P2P, Federation, Moderation, Recovery, Account (see method_ids)    |
  |                                                                        |
  +------------------------------------------------------------------------+

Key observations:

  1. The server never sees plaintext message content. MLS ciphertext is opaque to the DS -- it merely routes by recipientKey.

  2. KeyPackages are single-use (RFC 9420 requirement). The AS atomically removes a KeyPackage on fetch to enforce this invariant.

  3. QUIC + TLS 1.3 is the sole transport layer. The ALPN identifier is qpc.

  4. Push events (new messages, typing, presence, membership changes) are delivered server-to-client on QUIC uni-streams using a separate push frame format.


Protocol Layering

The system stacks three protocol layers:

  1. Transport -- QUIC + TLS 1.3. Provides confidentiality, integrity, and server authentication. See Protocol Stack.

  2. Framing / RPC -- Custom binary header + Protobuf serialisation. Each request frame is [method_id: u16][request_id: u32][payload_len: u32][protobuf]. Responses are [status: u8][request_id: u32][payload_len: u32][protobuf]. See Protobuf Framing.

  3. 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 nine workspace crates:

Crate Role
quicprochat-core Crypto primitives, MLS state machine, hybrid KEM
quicprochat-proto Cap'n Proto legacy types + Protobuf (prost) v2 generated types
quicprochat-kt Key transparency (append-only log, revocation)
quicprochat-plugin-api #![no_std] C-ABI plugin interface
quicprochat-rpc QUIC RPC framework: framing, server dispatch, client, middleware
quicprochat-sdk Client SDK: QpqClient, event broadcast, ConversationStore
quicprochat-server RPC server + domain services
quicprochat-client CLI/TUI client binary
quicprochat-p2p iroh P2P endpoint publish/resolve (feature-flagged)

See Crate Responsibilities for a full breakdown and dependency diagram.


Further Reading