feat: add post-quantum hybrid KEM + SQLCipher persistence
Feature 1 — Post-Quantum Hybrid KEM (X25519 + ML-KEM-768): - Create hybrid_kem.rs with keygen, encrypt, decrypt + 11 unit tests - Wire format: version(1) | x25519_eph_pk(32) | mlkem_ct(1088) | nonce(12) | ct - Add uploadHybridKey/fetchHybridKey RPCs to node.capnp schema - Server: hybrid key storage in FileBackedStore + RPC handlers - Client: hybrid keypair in StoredState, auto-wrap/unwrap in send/recv/invite/join - demo-group runs full hybrid PQ envelope round-trip Feature 2 — SQLCipher Persistence: - Extract Store trait from FileBackedStore API - Create SqlStore (rusqlite + bundled-sqlcipher) with encrypted-at-rest SQLite - Schema: key_packages, deliveries, hybrid_keys tables with indexes - Server CLI: --store-backend=sql, --db-path, --db-key flags - 5 unit tests for SqlStore (FIFO, round-trip, upsert, channel isolation) Also includes: client lib.rs refactor, auth config, TOML config file support, mdBook documentation, and various cleanups by user. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
171
docs/src/architecture/overview.md
Normal file
171
docs/src/architecture/overview.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Architecture Overview
|
||||
|
||||
quicnprotochat 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`](../wire-format/node-service-schema.md) as a unified
|
||||
`NodeService` interface.
|
||||
|
||||
See [Service Architecture](service-architecture.md) for per-method details,
|
||||
connection lifecycle, and the long-polling `fetchWait` mechanism.
|
||||
|
||||
---
|
||||
|
||||
## Dual-Key Model
|
||||
|
||||
quicnprotochat uses two independent asymmetric key pairs per client, each
|
||||
serving a distinct role:
|
||||
|
||||
```text
|
||||
quicnprotochat Key Model
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ X25519 static keypair (Noise transport) │
|
||||
│ ───────────────────────────────────── │
|
||||
│ - Generated once per node identity │
|
||||
│ - Used in the Noise_XX handshake (M1 stack) │
|
||||
│ - Provides mutual authentication + │
|
||||
│ channel confidentiality at the TCP layer │
|
||||
│ - Classical only (no PQ protection) │
|
||||
│ - Managed by NoiseKeypair, zeroize-on-drop │
|
||||
│ │
|
||||
│ 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 | X25519 (Noise) | Ed25519 (MLS) |
|
||||
|-------------------|-------------------------------------|--------------------------------------------|
|
||||
| Curve | Curve25519 (Montgomery) | Ed25519 (Twisted Edwards) |
|
||||
| Purpose | Transport authentication + secrecy | Identity binding, signing, MLS credentials |
|
||||
| Crate | `x25519-dalek` | `ed25519-dalek` |
|
||||
| Zeroize on drop | Yes (`StaticSecret`) | Yes (`Zeroizing<[u8; 32]>`) |
|
||||
| PQ protection | None (classical X25519) | MLS key schedule uses DHKEM(X25519); hybrid PQ KEM available at envelope level |
|
||||
|
||||
For details on the cryptographic properties of each key type, see
|
||||
[Ed25519 Identity Keys](../cryptography/identity-keys.md) and
|
||||
[X25519 Transport Keys](../cryptography/transport-keys.md).
|
||||
|
||||
---
|
||||
|
||||
## System Diagram
|
||||
|
||||
```text
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Alice Client │ │ Bob Client │
|
||||
│ │ │ │
|
||||
│ IdentityKeypair │ │ IdentityKeypair │
|
||||
│ (Ed25519) │ │ (Ed25519) │
|
||||
│ │ │ │
|
||||
│ GroupMember │ │ GroupMember │
|
||||
│ (MLS state) │ │ (MLS state) │
|
||||
│ │ │ │
|
||||
│ NoiseKeypair* │ │ NoiseKeypair* │
|
||||
│ (X25519, M1) │ │ (X25519, M1) │
|
||||
└────────┬─────────┘ └────────┬─────────┘
|
||||
│ │
|
||||
│ QUIC + TLS 1.3 (quinn/rustls) │
|
||||
│ ─── or ─── │
|
||||
│ Noise_XX over TCP (snow, M1 stack) │
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 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:**
|
||||
|
||||
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. The QUIC + TLS 1.3 stack is the primary transport (M3+). The Noise_XX over
|
||||
TCP stack from M1 remains available for environments where QUIC is blocked.
|
||||
|
||||
---
|
||||
|
||||
## Protocol Layering
|
||||
|
||||
The system stacks three protocol layers:
|
||||
|
||||
1. **Transport** -- QUIC + TLS 1.3 (primary) or Noise_XX over TCP (M1
|
||||
fallback). Provides confidentiality, integrity, and server authentication.
|
||||
See [Protocol Stack](protocol-stack.md).
|
||||
|
||||
2. **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](../protocol-layers/capn-proto.md).
|
||||
|
||||
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)](../protocol-layers/mls.md).
|
||||
|
||||
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](../protocol-layers/hybrid-kem.md).
|
||||
|
||||
---
|
||||
|
||||
## Crate Map
|
||||
|
||||
The implementation is split across four workspace crates:
|
||||
|
||||
| Crate | Role |
|
||||
|----------------------------|-------------------------------------------------------------------|
|
||||
| `quicnprotochat-core` | Crypto primitives, Noise transport, MLS state machine, hybrid KEM |
|
||||
| `quicnprotochat-proto` | Cap'n Proto schemas, codegen, and serialisation helpers |
|
||||
| `quicnprotochat-server` | QUIC listener, NodeService RPC, storage |
|
||||
| `quicnprotochat-client` | QUIC client, CLI subcommands, state persistence |
|
||||
|
||||
See [Crate Responsibilities](crate-responsibilities.md) for a full breakdown
|
||||
and dependency diagram.
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Protocol Stack](protocol-stack.md) -- layered comparison of the two transport stacks
|
||||
- [Service Architecture](service-architecture.md) -- NodeService RPC methods, connection lifecycle, long-polling
|
||||
- [End-to-End Data Flow](data-flow.md) -- registration, group creation, and message exchange sequence diagrams
|
||||
- [Wire Format Overview](../wire-format/overview.md) -- Cap'n Proto schema reference
|
||||
- [Cryptography Overview](../cryptography/overview.md) -- detailed cryptographic properties and threat model
|
||||
Reference in New Issue
Block a user