chore: rename project quicnprotochat -> quicproquo (binaries: qpq)
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>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Future Improvements
|
||||
|
||||
This document consolidates suggested improvements for quicnprotochat, drawn from the [roadmap](src/roadmap/milestones.md), [production readiness WBS](src/roadmap/production-readiness.md), [security audit](SECURITY-AUDIT.md), [production readiness audit](PRODUCTION-READINESS-AUDIT.md), and [future research](src/roadmap/future-research.md). Items are grouped by theme and ordered by impact and dependency.
|
||||
This document consolidates suggested improvements for quicproquo, drawn from the [roadmap](src/roadmap/milestones.md), [production readiness WBS](src/roadmap/production-readiness.md), [security audit](SECURITY-AUDIT.md), [production readiness audit](PRODUCTION-READINESS-AUDIT.md), and [future research](src/roadmap/future-research.md). Items are grouped by theme and ordered by impact and dependency.
|
||||
|
||||
---
|
||||
|
||||
@@ -98,7 +98,7 @@ This document consolidates suggested improvements for quicnprotochat, drawn from
|
||||
### 4.5 Docker user and writable paths
|
||||
|
||||
- **Current:** Image runs as `nobody`; data dir may not be writable.
|
||||
- **Improve:** Create a dedicated user/group in the image and set `QUICNPROTOCHAT_DATA_DIR` (and cert paths) to a directory writable by that user; document in deployment docs.
|
||||
- **Improve:** Create a dedicated user/group in the image and set `QPQ_DATA_DIR` (and cert paths) to a directory writable by that user; document in deployment docs.
|
||||
- **Ref:** [Production readiness audit § 15](PRODUCTION-READINESS-AUDIT.md).
|
||||
|
||||
---
|
||||
@@ -133,7 +133,7 @@ This document consolidates suggested improvements for quicnprotochat, drawn from
|
||||
### 6.1 P2P / NAT traversal (iroh, LibP2P)
|
||||
|
||||
- **Goal:** Direct peer-to-peer when possible; server as optional relay/rendezvous. Reduces single-point-of-failure and can improve latency.
|
||||
- **Ref:** [Future research § LibP2P / iroh](src/roadmap/future-research.md). The `quicnprotochat-p2p` crate is a starting point.
|
||||
- **Ref:** [Future research § LibP2P / iroh](src/roadmap/future-research.md). The `quicproquo-p2p` crate is a starting point.
|
||||
|
||||
### 6.2 WebTransport (browser client)
|
||||
|
||||
@@ -175,8 +175,10 @@ This document consolidates suggested improvements for quicnprotochat, drawn from
|
||||
|
||||
## Related documents
|
||||
|
||||
- **[ROADMAP.md](../ROADMAP.md)** — phased execution plan (Phases 1–8) incorporating all items below
|
||||
- [Milestones](src/roadmap/milestones.md) — M7 and beyond
|
||||
- [Production readiness WBS](src/roadmap/production-readiness.md) — phased hardening
|
||||
- [Future research](src/roadmap/future-research.md) — technologies and options
|
||||
- [Security audit](SECURITY-AUDIT.md) — recommendations and status
|
||||
- [Production readiness audit](PRODUCTION-READINESS-AUDIT.md) — checklist and fixes
|
||||
- [ADR-006: SDK-First Adoption](src/design-rationale/adr-006-rest-gateway.md) — no REST gateway, native QUIC SDKs
|
||||
|
||||
@@ -9,21 +9,21 @@ This document splits work for **Future Improvements §1 (Security and hardening)
|
||||
**Owns:** Server auth/OPAQUE, TLS config, core crypto (identity, keypackage, hybrid_kem), docs under `docs/src/cryptography/` and TLS/cert docs.
|
||||
|
||||
### A1. 1.2 CA-signed TLS / certificate lifecycle
|
||||
- **Files:** `docs/src/getting-started/` (new or existing), `crates/quicnprotochat-server/src/tls.rs` (optional env), `README.md`.
|
||||
- **Files:** `docs/src/getting-started/` (new or existing), `crates/quicproquo-server/src/tls.rs` (optional env), `README.md`.
|
||||
- **Tasks:**
|
||||
1. Add **Certificate lifecycle** doc: using CA-issued certs (e.g. Let's Encrypt), cert rotation, OCSP/CRL optional. Recommend pinning for single-server.
|
||||
2. Optional: server config or env to prefer CA-signed cert path (e.g. `QUICNPROTOCHAT_USE_CA_CERT=1` and read from a different path). Low priority if docs suffice.
|
||||
2. Optional: server config or env to prefer CA-signed cert path (e.g. `QPQ_USE_CA_CERT=1` and read from a different path). Low priority if docs suffice.
|
||||
- **Deliverable:** `docs/src/getting-started/certificate-lifecycle.md` (or section in running-the-server) + README link.
|
||||
|
||||
### A2. 1.4 Username enumeration (OPAQUE)
|
||||
- **Files:** `crates/quicnprotochat-server/src/node_service/auth_ops.rs`, `docs/SECURITY-AUDIT.md`.
|
||||
- **Files:** `crates/quicproquo-server/src/node_service/auth_ops.rs`, `docs/SECURITY-AUDIT.md`.
|
||||
- **Tasks:**
|
||||
1. Document the risk in SECURITY-AUDIT (already mentioned).
|
||||
2. Optional mitigation: ensure `get_user_record` is always called before `ServerLogin::start` (already true). If desired, add a constant-time delay or dummy work when user not found so response timing does not leak existence. Keep OPAQUE security unchanged.
|
||||
- **Deliverable:** Doc update; optional small code change in `handle_opaque_login_start`.
|
||||
|
||||
### A3. 1.1 M7 — Post-quantum MLS
|
||||
- **Files:** `crates/quicnprotochat-core/src/` (new or modified crypto provider), `crates/quicnprotochat-core/src/group.rs`, `crates/quicnprotochat-core/src/hybrid_kem.rs`, `crates/quicnprotochat-core/src/hybrid_crypto.rs`.
|
||||
- **Files:** `crates/quicproquo-core/src/` (new or modified crypto provider), `crates/quicproquo-core/src/group.rs`, `crates/quicproquo-core/src/hybrid_kem.rs`, `crates/quicproquo-core/src/hybrid_crypto.rs`.
|
||||
- **Tasks:**
|
||||
1. Implement a custom `OpenMlsCryptoProvider` (or adapter) that uses hybrid X25519 + ML-KEM-768 for MLS KEM (HPKE layer).
|
||||
2. Wire hybrid shared secret derivation (see milestones M7) into the provider.
|
||||
@@ -42,7 +42,7 @@ This document splits work for **Future Improvements §1 (Security and hardening)
|
||||
**Owns:** Cap'n Proto schema (node.capnp delivery/channel methods), server storage (Store trait, FileBackedStore, SqlStore), `node_service/delivery.rs`, `node_service/key_ops.rs` (if createChannel lives there), client commands for channels.
|
||||
|
||||
### B1. 5.1 Private 1:1 channels (DM)
|
||||
- **Files:** `schemas/node.capnp`, `crates/quicnprotochat-server/src/storage.rs`, `crates/quicnprotochat-server/src/sql_store.rs`, `crates/quicnprotochat-server/src/node_service/delivery.rs`, new `crates/quicnprotochat-server/src/node_service/channel_ops.rs` (or add to delivery), migrations for channels table.
|
||||
- **Files:** `schemas/node.capnp`, `crates/quicproquo-server/src/storage.rs`, `crates/quicproquo-server/src/sql_store.rs`, `crates/quicproquo-server/src/node_service/delivery.rs`, new `crates/quicproquo-server/src/node_service/channel_ops.rs` (or add to delivery), migrations for channels table.
|
||||
- **Tasks:**
|
||||
1. **Schema:** Add `createChannel @N (auth :Auth, peerKey :Data) -> (channelId :Data);` to `node.capnp`. Rebuild proto.
|
||||
2. **Store trait:** Add `create_channel(&self, member_a: &[u8], member_b: &[u8]) -> Result<Vec<u8>, StorageError>`, `get_channel_members(&self, channel_id: &[u8]) -> Result<Option<(Vec<u8>, Vec<u8>)>, StorageError>`. Implement in FileBackedStore (in-memory map channel_id -> (a, b)) and SqlStore (channels table, unique on sorted (a,b)).
|
||||
@@ -53,7 +53,7 @@ This document splits work for **Future Improvements §1 (Security and hardening)
|
||||
- **Ref:** [DM channels design](src/roadmap/dm-channels.md).
|
||||
|
||||
### B2. 5.2 MLS lifecycle (remove, update, proposals)
|
||||
- **Files:** `crates/quicnprotochat-core/src/group.rs`, client commands that use GroupMember.
|
||||
- **Files:** `crates/quicproquo-core/src/group.rs`, client commands that use GroupMember.
|
||||
- **Tasks:**
|
||||
1. Add `remove_member` (by index or identity) and `update_credential` / rekey using openmls APIs.
|
||||
2. Handle incoming MLS proposals (Remove, Update) in `receive_message` path and apply to group state.
|
||||
@@ -62,7 +62,7 @@ This document splits work for **Future Improvements §1 (Security and hardening)
|
||||
- **Ref:** OpenMLS API for `MlsGroup::remove_member`, `MlsGroup::process_pending_proposals`, etc.
|
||||
|
||||
### B3. 5.3 Sealed Sender and 5.4 Traffic analysis
|
||||
- **Files:** Docs; optionally `crates/quicnprotochat-server`, `crates/quicnprotochat-client` for padding.
|
||||
- **Files:** Docs; optionally `crates/quicproquo-server`, `crates/quicproquo-client` for padding.
|
||||
- **Tasks:**
|
||||
1. Document current `sealed_sender` behaviour (enqueue without identity binding) and that full “sender in ciphertext” is a future protocol change.
|
||||
2. Optional: add optional payload padding (e.g. pad to next 256 bytes) or random delay in client send path for 5.4.
|
||||
@@ -75,12 +75,12 @@ This document splits work for **Future Improvements §1 (Security and hardening)
|
||||
| Area | Agent A | Agent B |
|
||||
|------|---------|---------|
|
||||
| `schemas/node.capnp` | — | Add createChannel |
|
||||
| `crates/quicnprotochat-server/src/node_service/auth_ops.rs` | 1.4 username enum | — |
|
||||
| `crates/quicnprotochat-server/src/node_service/delivery.rs` | — | 5.1 channel authz |
|
||||
| `crates/quicnprotochat-server/src/storage.rs` | — | 5.1 Store channel methods |
|
||||
| `crates/quicnprotochat-server/src/sql_store.rs` | — | 5.1 channels table + impl |
|
||||
| `crates/quicnprotochat-server/src/tls.rs` | 1.2 optional | — |
|
||||
| `crates/quicnprotochat-core/` | 1.1 M7, 1.3 doc | 5.2 group.rs |
|
||||
| `crates/quicproquo-server/src/node_service/auth_ops.rs` | 1.4 username enum | — |
|
||||
| `crates/quicproquo-server/src/node_service/delivery.rs` | — | 5.1 channel authz |
|
||||
| `crates/quicproquo-server/src/storage.rs` | — | 5.1 Store channel methods |
|
||||
| `crates/quicproquo-server/src/sql_store.rs` | — | 5.1 channels table + impl |
|
||||
| `crates/quicproquo-server/src/tls.rs` | 1.2 optional | — |
|
||||
| `crates/quicproquo-core/` | 1.1 M7, 1.3 doc | 5.2 group.rs |
|
||||
| `docs/` | 1.2, 1.3, 1.4, 5.3/5.4 | — (or shared) |
|
||||
|
||||
**Shared:** `docs/`, `README.md`. Prefer non-overlapping files (e.g. A adds `certificate-lifecycle.md`, B does not edit it).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Production Readiness Audit
|
||||
|
||||
This document summarizes issues and fixes needed to get quicnprotochat production-ready, based on a codebase review. It aligns with the existing [Production Readiness WBS](src/roadmap/production-readiness.md) and [Coding Standards](src/contributing/coding-standards.md).
|
||||
This document summarizes issues and fixes needed to get quicproquo production-ready, based on a codebase review. It aligns with the existing [Production Readiness WBS](src/roadmap/production-readiness.md) and [Coding Standards](src/contributing/coding-standards.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -10,7 +10,7 @@ This document summarizes issues and fixes needed to get quicnprotochat productio
|
||||
|
||||
- **README and example config** use `auth_token = "devtoken"` and `db_key = ""`.
|
||||
- **Risk:** Deploying with default/example config allows weak or no auth and unencrypted DB.
|
||||
- **Fix:** Require explicit `QUICNPROTOCHAT_AUTH_TOKEN` (or config) in production; reject empty or `"devtoken"` when a production mode/env is set. Document that `db_key` empty disables SQLCipher and is not acceptable for production.
|
||||
- **Fix:** Require explicit `QPQ_AUTH_TOKEN` (or config) in production; reject empty or `"devtoken"` when a production mode/env is set. Document that `db_key` empty disables SQLCipher and is not acceptable for production.
|
||||
|
||||
### 2. **Database encryption optional**
|
||||
|
||||
@@ -19,15 +19,15 @@ This document summarizes issues and fixes needed to get quicnprotochat productio
|
||||
|
||||
### 3. **Secrets and generated files not ignored**
|
||||
|
||||
- **`.gitignore`** does not include `data/`, so `data/server-cert.der`, `data/server-key.der`, and `data/quicnprotochat.db` could be committed.
|
||||
- **`.gitignore`** does not include `data/`, so `data/server-cert.der`, `data/server-key.der`, and `data/qpq.db` could be committed.
|
||||
- **Fix:** Add `data/` (and any other dirs that hold certs, keys, or DBs) to `.gitignore`. Consider adding `*.der` and `*.db` if used only for local/dev.
|
||||
|
||||
### 4. **Dockerfile out of sync with workspace**
|
||||
|
||||
- **Workspace** has 5 members including `crates/quicnprotochat-p2p`.
|
||||
- **Dockerfile** only copies 4 crate manifests and creates stub dirs for those 4; it never copies `quicnprotochat-p2p`.
|
||||
- **Result:** `cargo build --release --bin quicnprotochat-server` can fail (missing workspace member) or behave inconsistently.
|
||||
- **Fix:** Add `COPY crates/quicnprotochat-p2p/Cargo.toml` and a stub `crates/quicnprotochat-p2p/src` (or equivalent) in the dependency-cache layer so the workspace resolves. Ensure the final `COPY crates/ crates/` still brings in real p2p source.
|
||||
- **Workspace** has 5 members including `crates/quicproquo-p2p`.
|
||||
- **Dockerfile** only copies 4 crate manifests and creates stub dirs for those 4; it never copies `quicproquo-p2p`.
|
||||
- **Result:** `cargo build --release --bin quicproquo-server` can fail (missing workspace member) or behave inconsistently.
|
||||
- **Fix:** Add `COPY crates/quicproquo-p2p/Cargo.toml` and a stub `crates/quicproquo-p2p/src` (or equivalent) in the dependency-cache layer so the workspace resolves. Ensure the final `COPY crates/ crates/` still brings in real p2p source.
|
||||
|
||||
### 5. **E2E test failing (rustls CryptoProvider)**
|
||||
|
||||
@@ -41,7 +41,7 @@ This document summarizes issues and fixes needed to get quicnprotochat productio
|
||||
|
||||
### 6. **Panic risk in client RPC path**
|
||||
|
||||
- **`quicnprotochat-client/src/lib.rs`:** `set_auth()` uses `.expect("init_auth must be called with a non-empty token before RPCs")`. If RPC is called without `init_auth`, the process panics.
|
||||
- **`quicproquo-client/src/lib.rs`:** `set_auth()` uses `.expect("init_auth must be called with a non-empty token before RPCs")`. If RPC is called without `init_auth`, the process panics.
|
||||
- **Fix:** Replace with a `Result` or an error return (e.g. a dedicated error type) so callers get a recoverable error instead of a panic. Document that `init_auth` must be called before RPCs.
|
||||
|
||||
### 7. **Mutex `.unwrap()` in production paths**
|
||||
@@ -95,7 +95,7 @@ This document summarizes issues and fixes needed to get quicnprotochat productio
|
||||
### 15. **Docker image runs as `nobody`**
|
||||
|
||||
- **Dockerfile** uses `USER nobody`. Good for not running as root, but `nobody` may not have a writable home or data dir.
|
||||
- **Fix:** Ensure `QUICNPROTOCHAT_DATA_DIR` (and cert paths) point to a directory writable by `nobody`, or create a dedicated user/group with a known UID and use that in the Dockerfile and docs.
|
||||
- **Fix:** Ensure `QPQ_DATA_DIR` (and cert paths) point to a directory writable by `nobody`, or create a dedicated user/group with a known UID and use that in the Dockerfile and docs.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Security Audit
|
||||
|
||||
This document is a security audit of the quicnprotochat codebase as of the audit date. It aligns with the [Threat Model](src/cryptography/threat-model.md) and [Production Readiness Audit](PRODUCTION-READINESS-AUDIT.md). The project has **not** undergone a formal third-party audit; this is an internal review.
|
||||
This document is a security audit of the quicproquo codebase as of the audit date. It aligns with the [Threat Model](src/cryptography/threat-model.md) and [Production Readiness Audit](PRODUCTION-READINESS-AUDIT.md). The project has **not** undergone a formal third-party audit; this is an internal review.
|
||||
|
||||
---
|
||||
|
||||
@@ -24,19 +24,19 @@ This document is a security audit of the quicnprotochat codebase as of the audit
|
||||
|
||||
### 1.1 Token comparison
|
||||
|
||||
- **Location:** `crates/quicnprotochat-server/src/auth.rs`
|
||||
- **Location:** `crates/quicproquo-server/src/auth.rs`
|
||||
- **Finding:** Bearer token and identity key comparisons use `subtle::ConstantTimeEq` (`ct_eq`). Length is checked before comparison where applicable.
|
||||
- **Status:** ✅ No timing leakage from token or identity comparison.
|
||||
|
||||
### 1.2 Session token generation
|
||||
|
||||
- **Location:** `crates/quicnprotochat-server/src/node_service/auth_ops.rs` (login finish)
|
||||
- **Location:** `crates/quicproquo-server/src/node_service/auth_ops.rs` (login finish)
|
||||
- **Finding:** Session tokens are 32 bytes from `rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut token)`. Stored in `sessions` with TTL (24h). Expired sessions are removed on next use.
|
||||
- **Status:** ✅ Cryptographically strong, single-use style (opaque 32-byte token).
|
||||
|
||||
### 1.3 OPAQUE (RFC 9497)
|
||||
|
||||
- **Location:** `crates/quicnprotochat-core/src/opaque_auth.rs`, server `auth_ops.rs`
|
||||
- **Location:** `crates/quicproquo-core/src/opaque_auth.rs`, server `auth_ops.rs`
|
||||
- **Finding:** Shared `OpaqueSuite` (Ristretto255, Triple-DH, Argon2id). Server never sees password. Registration and login flows use `ServerRegistration`/`ServerLogin` correctly. Pending login state is stored server-side and removed on consume. Identity key is bound at login finish; mismatch returns E016 and is not logged with secrets.
|
||||
- **DoS:** Pending-login check runs **before** expensive OPAQUE work (login start); repeated attempts for the same username within 60s are rejected early.
|
||||
- **Status:** ✅ Correct usage; DoS mitigation in place.
|
||||
@@ -52,19 +52,19 @@ This document is a security audit of the quicnprotochat codebase as of the audit
|
||||
|
||||
### 2.1 MLS and identity
|
||||
|
||||
- **Location:** `quicnprotochat-core` (group, identity, keypackage)
|
||||
- **Location:** `quicproquo-core` (group, identity, keypackage)
|
||||
- **Finding:** MLS ciphersuite `MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519` (RFC 9420). Ed25519 identity seed stored in `Zeroizing<[u8; 32]>`; zeroize-on-drop. KeyPackages validated for ciphersuite before server stores. Single-use KeyPackage semantics enforced (consume-on-fetch).
|
||||
- **Status:** ✅ Aligns with key lifecycle and zeroization goals.
|
||||
|
||||
### 2.2 Hybrid KEM (X25519 + ML-KEM-768)
|
||||
|
||||
- **Location:** `crates/quicnprotochat-core/src/hybrid_kem.rs`
|
||||
- **Finding:** Hybrid keypair and shared secrets use `Zeroizing` where appropriate. HKDF domain separation (`quicnprotochat-hybrid-v1`). ChaCha20-Poly1305 for AEAD. Versioned envelope.
|
||||
- **Location:** `crates/quicproquo-core/src/hybrid_kem.rs`
|
||||
- **Finding:** Hybrid keypair and shared secrets use `Zeroizing` where appropriate. HKDF domain separation (`quicproquo-hybrid-v1`). ChaCha20-Poly1305 for AEAD. Versioned envelope.
|
||||
- **Status:** ✅ PQ-ready envelope layer; secret handling is careful.
|
||||
|
||||
### 2.3 Client state encryption (QPCE)
|
||||
|
||||
- **Location:** `crates/quicnprotochat-client/src/client/state.rs`
|
||||
- **Location:** `crates/quicproquo-client/src/client/state.rs`
|
||||
- **Finding:** Optional password protection: Argon2id (default params) for key derivation, ChaCha20-Poly1305, random salt and nonce. Derived key held in `Zeroizing` during use. Unencrypted state is a documented option (e.g. dev).
|
||||
- **Recommendation:** Document Argon2 params (memory, iterations) for auditability; consider explicit `Argon2::new()` with named params in a future revision.
|
||||
- **Status:** ✅ Appropriate for optional at-rest protection.
|
||||
@@ -75,13 +75,13 @@ This document is a security audit of the quicnprotochat codebase as of the audit
|
||||
|
||||
### 3.1 Server TLS
|
||||
|
||||
- **Location:** `crates/quicnprotochat-server/src/tls.rs`
|
||||
- **Location:** `crates/quicproquo-server/src/tls.rs`
|
||||
- **Finding:** TLS 1.3 only. No client cert. ALPN `capnp`. When not in production, missing cert/key triggers self-signed generation; key file permissions set to `0o600` on Unix. Production mode requires existing cert/key (no auto-generation).
|
||||
- **Status:** ✅ Matches documented design; self-signed limitation is documented in threat model.
|
||||
|
||||
### 3.2 Client TLS
|
||||
|
||||
- **Location:** `crates/quicnprotochat-client/src/client/rpc.rs`
|
||||
- **Location:** `crates/quicproquo-client/src/client/rpc.rs`
|
||||
- **Finding:** Client loads CA cert from file, builds `RootCertStore` with that single cert, uses it for server verification. Server name from CLI/env is used for connection (SNI and cert verification). No custom bypass.
|
||||
- **Status:** ✅ Proper verification against provided CA; trust-on-first-use / self-signed caveat is documented.
|
||||
|
||||
@@ -106,7 +106,7 @@ This document is a security audit of the quicnprotochat codebase as of the audit
|
||||
|
||||
### 4.2 Rate limiting
|
||||
|
||||
- **Location:** `crates/quicnprotochat-server/src/auth.rs`, `delivery.rs`
|
||||
- **Location:** `crates/quicproquo-server/src/auth.rs`, `delivery.rs`
|
||||
- **Finding:** Per-token rate limit (e.g. 100 enqueues per 60s). Enqueue path checks before storage. Queue depth and payload size caps (1000 messages, 5 MB) enforced.
|
||||
- **Status:** ✅ Limits in place to curb abuse and DoS.
|
||||
|
||||
@@ -156,11 +156,11 @@ These remain as documented, not new findings:
|
||||
### 8.1 High value
|
||||
|
||||
- **Dependency audit:** Run `cargo install cargo-audit` then `cargo audit` locally (and in CI if available) to check for known-vulnerable dependencies. Fix or document any findings. See [Checking dependencies](#checking-dependencies) below.
|
||||
- **Argon2 params:** Implemented: client state KDF now uses explicit Argon2id parameters (19 MiB memory, 2 iterations, 1 lane) in `quicnprotochat-client` so they are auditable.
|
||||
- **Argon2 params:** Implemented: client state KDF now uses explicit Argon2id parameters (19 MiB memory, 2 iterations, 1 lane) in `quicproquo-client` so they are auditable.
|
||||
|
||||
### 8.2 Medium value
|
||||
|
||||
- **Certificate pinning:** To pin the server, use the server's certificate as the client's `ca_cert` (e.g. copy `server-cert.der` from the server and pass it via `--ca-cert` or `QUICNPROTOCHAT_CA_CERT`). Do not use a general CA unless you intend to trust that CA for all servers. See [Certificate pinning](#certificate-pinning) below.
|
||||
- **Certificate pinning:** To pin the server, use the server's certificate as the client's `ca_cert` (e.g. copy `server-cert.der` from the server and pass it via `--ca-cert` or `QPQ_CA_CERT`). Do not use a general CA unless you intend to trust that CA for all servers. See [Certificate pinning](#certificate-pinning) below.
|
||||
- **Health endpoint:** The `health` RPC is unauthenticated by design for liveness probes and load balancers; this is documented in code and in this audit.
|
||||
|
||||
### 8.3 Lower priority
|
||||
@@ -208,7 +208,7 @@ Fix or document any reported issues. Running `cargo audit` in CI (e.g. GitHub Ac
|
||||
|
||||
## Certificate pinning
|
||||
|
||||
The client trusts the server certificate(s) in the file given by `--ca-cert` (or `QUICNPROTOCHAT_CA_CERT`). To **pin** a specific server:
|
||||
The client trusts the server certificate(s) in the file given by `--ca-cert` (or `QPQ_CA_CERT`). To **pin** a specific server:
|
||||
|
||||
1. Obtain the server's certificate (e.g. copy `data/server-cert.der` from the server, or export from your deployment).
|
||||
2. Use that file as the client's `ca_cert`. The client will only connect to a server that presents that exact certificate (or chain).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[book]
|
||||
title = "quicnprotochat"
|
||||
title = "quicproquo"
|
||||
description = "End-to-end encrypted group messaging over QUIC + TLS 1.3 + MLS (RFC 9420)"
|
||||
authors = ["quicnprotochat contributors"]
|
||||
authors = ["quicproquo contributors"]
|
||||
language = "en"
|
||||
src = "src"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
# Why quicnprotochat?
|
||||
# Why quicproquo?
|
||||
|
||||
- [Comparison with Classical Chat Protocols](design-rationale/protocol-comparison.md)
|
||||
- [Why This Design, Not Signal/Matrix/...](design-rationale/why-not-signal.md)
|
||||
@@ -71,6 +71,7 @@
|
||||
- [ADR-002: Cap'n Proto over MessagePack](design-rationale/adr-002-capnproto.md)
|
||||
- [ADR-004: MLS-Unaware Delivery Service](design-rationale/adr-004-mls-unaware-ds.md)
|
||||
- [ADR-005: Single-Use KeyPackages](design-rationale/adr-005-single-use-keypackages.md)
|
||||
- [ADR-006: SDK-First Adoption (No REST Gateway)](design-rationale/adr-006-rest-gateway.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -92,6 +93,7 @@
|
||||
- [Auth, Devices, and Tokens](roadmap/authz-plan.md)
|
||||
- [1:1 Channel Design](roadmap/dm-channels.md)
|
||||
- [Future Research Directions](roadmap/future-research.md)
|
||||
- [Full Roadmap (Phases 1–8)](../../ROADMAP.md)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Glossary
|
||||
|
||||
Alphabetical glossary of terms used throughout the quicnprotochat documentation.
|
||||
Alphabetical glossary of terms used throughout the quicproquo documentation.
|
||||
Each entry includes a brief definition and, where applicable, a reference to the
|
||||
relevant specification or documentation page.
|
||||
|
||||
---
|
||||
|
||||
**AEAD** -- Authenticated Encryption with Associated Data. A symmetric encryption
|
||||
scheme that provides both confidentiality and integrity. quicnprotochat uses
|
||||
scheme that provides both confidentiality and integrity. quicproquo uses
|
||||
AES-128-GCM (in the MLS ciphersuite). See [Cryptography Overview](../cryptography/overview.md).
|
||||
|
||||
**ALPN** -- Application-Layer Protocol Negotiation. A TLS extension that allows
|
||||
the client and server to agree on an application protocol during the TLS
|
||||
handshake. quicnprotochat uses the ALPN token `b"capnp"` to identify Cap'n Proto
|
||||
handshake. quicproquo uses the ALPN token `b"capnp"` to identify Cap'n Proto
|
||||
RPC connections. See [QUIC + TLS 1.3](../protocol-layers/quic-tls.md).
|
||||
|
||||
**AS** -- Authentication Service. The server component that stores and
|
||||
@@ -21,7 +21,7 @@ generation; peers fetch them to add new members to a group.
|
||||
See [Architecture Overview](../architecture/overview.md).
|
||||
|
||||
**Cap'n Proto** -- A zero-copy serialisation format with a built-in RPC system.
|
||||
quicnprotochat uses Cap'n Proto for all wire messages and service RPCs. Schemas
|
||||
quicproquo uses Cap'n Proto for all wire messages and service RPCs. Schemas
|
||||
live in `schemas/*.capnp` and are compiled to Rust at build time.
|
||||
See [Cap'n Proto Serialisation and RPC](../protocol-layers/capn-proto.md).
|
||||
|
||||
@@ -32,13 +32,13 @@ forward secrecy and post-compromise security.
|
||||
See [MLS (RFC 9420)](../protocol-layers/mls.md).
|
||||
|
||||
**Credential** -- An MLS identity binding that associates a member's signing key
|
||||
with their identity. quicnprotochat uses `BasicCredential`, which contains the
|
||||
with their identity. quicproquo uses `BasicCredential`, which contains the
|
||||
raw Ed25519 public key bytes. See
|
||||
[Ed25519 Identity Keys](../cryptography/identity-keys.md).
|
||||
|
||||
**DER** -- Distinguished Encoding Rules. A binary encoding format for ASN.1
|
||||
structures, used for X.509 certificates and TLS certificate chains. The
|
||||
self-signed TLS certificate generated by quicnprotochat is DER-encoded.
|
||||
self-signed TLS certificate generated by quicproquo is DER-encoded.
|
||||
|
||||
**DS** -- Delivery Service. The server component that provides store-and-forward
|
||||
relay for opaque MLS payloads. The DS never inspects ciphertext -- it routes
|
||||
@@ -47,7 +47,7 @@ See [Architecture Overview](../architecture/overview.md).
|
||||
|
||||
**Ed25519** -- Edwards-curve Digital Signature Algorithm on Curve25519. Used for
|
||||
MLS identity credentials and signing (KeyPackages, Commits, group operations).
|
||||
quicnprotochat uses the `ed25519-dalek` crate.
|
||||
quicproquo uses the `ed25519-dalek` crate.
|
||||
See [Ed25519 Identity Keys](../cryptography/identity-keys.md).
|
||||
|
||||
**Epoch** -- The version number of an MLS group's key state. Each Commit
|
||||
@@ -61,11 +61,11 @@ the epoch ratchet: key material from earlier epochs is deleted when the epoch
|
||||
advances. See [Forward Secrecy](../cryptography/forward-secrecy.md).
|
||||
|
||||
**HKDF** -- HMAC-based Key Derivation Function. Used in MLS to derive symmetric
|
||||
keys from shared secrets. quicnprotochat uses HKDF-SHA256.
|
||||
keys from shared secrets. quicproquo uses HKDF-SHA256.
|
||||
|
||||
**HPKE** -- Hybrid Public Key Encryption. The public-key encryption scheme used
|
||||
in MLS for key exchange (encrypting to a KeyPackage's init key). Defined in
|
||||
RFC 9180. In quicnprotochat, HPKE uses DHKEM(X25519, HKDF-SHA256).
|
||||
RFC 9180. In quicproquo, HPKE uses DHKEM(X25519, HKDF-SHA256).
|
||||
See [Hybrid KEM](../protocol-layers/hybrid-kem.md).
|
||||
|
||||
**KEM** -- Key Encapsulation Mechanism. A cryptographic primitive that generates
|
||||
@@ -80,7 +80,7 @@ is consumed on fetch. See
|
||||
|
||||
**ML-KEM-768** -- Module-Lattice-based Key Encapsulation Mechanism, security
|
||||
level 3 (NIST FIPS 203). A post-quantum KEM based on the hardness of the
|
||||
module learning-with-errors (MLWE) problem. quicnprotochat plans to use ML-KEM-768
|
||||
module learning-with-errors (MLWE) problem. quicproquo plans to use ML-KEM-768
|
||||
in a hybrid construction with X25519 at milestone M7.
|
||||
See [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md).
|
||||
|
||||
@@ -104,7 +104,7 @@ See [Future Research](../roadmap/future-research.md).
|
||||
**QUIC** -- A UDP-based, multiplexed, encrypted transport protocol defined in
|
||||
RFC 9000. QUIC integrates TLS 1.3 for authentication and confidentiality and
|
||||
provides 0-RTT connection establishment, stream multiplexing, and built-in
|
||||
congestion control. quicnprotochat uses the `quinn` crate.
|
||||
congestion control. quicproquo uses the `quinn` crate.
|
||||
See [QUIC + TLS 1.3](../protocol-layers/quic-tls.md).
|
||||
|
||||
**Ratchet Tree** -- The binary tree data structure used in MLS for efficient
|
||||
@@ -113,7 +113,7 @@ hold derived key material. Updates propagate along the path from a leaf to the
|
||||
root, giving O(log N) cost for key updates in a group of N members.
|
||||
|
||||
**TLS 1.3** -- Transport Layer Security version 1.3, defined in RFC 8446. The
|
||||
standard for authenticated, encrypted transport. quicnprotochat uses TLS 1.3
|
||||
standard for authenticated, encrypted transport. quicproquo uses TLS 1.3
|
||||
exclusively (via `rustls` with `TLS13` cipher suites only) as part of the QUIC
|
||||
transport. See [QUIC + TLS 1.3](../protocol-layers/quic-tls.md).
|
||||
|
||||
@@ -125,11 +125,11 @@ KeyPackage. See [MLS (RFC 9420)](../protocol-layers/mls.md).
|
||||
**X25519** -- Elliptic curve Diffie-Hellman key exchange on Curve25519 (using
|
||||
the Montgomery form). Used as the classical component of DHKEM in MLS HPKE
|
||||
and in the hybrid KEM (X25519 + ML-KEM-768).
|
||||
quicnprotochat uses the `x25519-dalek` crate.
|
||||
quicproquo uses the `x25519-dalek` crate.
|
||||
See [Cryptography Overview](../cryptography/overview.md).
|
||||
|
||||
**Zeroize** -- The practice of securely clearing sensitive data (private keys,
|
||||
shared secrets) from memory when it is no longer needed. quicnprotochat uses the
|
||||
shared secrets) from memory when it is no longer needed. quicproquo uses the
|
||||
`zeroize` crate with the `ZeroizeOnDrop` derive macro to ensure that key material
|
||||
is overwritten on drop.
|
||||
See [Key Lifecycle and Zeroization](../cryptography/key-lifecycle.md).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# References and Further Reading
|
||||
|
||||
This page collects the standards, crate documentation, and research papers
|
||||
referenced throughout the quicnprotochat documentation. Entries are organised by
|
||||
referenced throughout the quicproquo documentation. Entries are organised by
|
||||
category.
|
||||
|
||||
---
|
||||
@@ -10,21 +10,21 @@ category.
|
||||
|
||||
| Reference | Description |
|
||||
|-----------|-------------|
|
||||
| [RFC 9420 -- The Messaging Layer Security (MLS) Protocol](https://datatracker.ietf.org/doc/rfc9420/) | The group key agreement protocol used by quicnprotochat. Defines KeyPackages, Welcome messages, Commits, the ratchet tree, epoch advancement, and the security properties (forward secrecy, post-compromise security). See [MLS (RFC 9420)](../protocol-layers/mls.md). |
|
||||
| [RFC 9000 -- QUIC: A UDP-Based Multiplexed and Secure Transport](https://datatracker.ietf.org/doc/rfc9000/) | The transport protocol underlying quicnprotochat's primary connection layer. Provides multiplexed streams, 0-RTT connection establishment, and built-in congestion control. See [QUIC + TLS 1.3](../protocol-layers/quic-tls.md). |
|
||||
| [RFC 9001 -- Using TLS to Secure QUIC](https://datatracker.ietf.org/doc/rfc9001/) | Defines how TLS 1.3 is integrated into QUIC for authentication and key exchange. quicnprotochat uses this via the `quinn` + `rustls` stack. |
|
||||
| [RFC 8446 -- The Transport Layer Security (TLS) Protocol Version 1.3](https://datatracker.ietf.org/doc/rfc8446/) | The TLS version used exclusively by quicnprotochat (no TLS 1.2 fallback). Provides the handshake, key schedule, and record layer for QUIC transport security. |
|
||||
| [RFC 9180 -- Hybrid Public Key Encryption (HPKE)](https://datatracker.ietf.org/doc/rfc9180/) | The public-key encryption scheme used internally by MLS for encrypting to KeyPackage init keys. quicnprotochat's MLS ciphersuite uses DHKEM(X25519, HKDF-SHA256) with AES-128-GCM. |
|
||||
| [NIST FIPS 203 -- Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM)](https://csrc.nist.gov/pubs/fips/203/final) | The post-quantum KEM standard. quicnprotochat plans to use ML-KEM-768 in a hybrid construction with X25519 at milestone M7. See [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md). |
|
||||
| [Cap'n Proto specification](https://capnproto.org/) | The zero-copy serialisation format and RPC system used for all quicnprotochat wire messages and service interfaces. See [Cap'n Proto Serialisation and RPC](../protocol-layers/capn-proto.md). |
|
||||
| [draft-ietf-tls-hybrid-design -- Hybrid Key Exchange in TLS 1.3](https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/) | The combiner approach used by quicnprotochat's hybrid KEM construction (X25519 shared secret concatenated with ML-KEM-768 shared secret, fed through HKDF). See [Hybrid KEM](../protocol-layers/hybrid-kem.md). |
|
||||
| [RFC 9420 -- The Messaging Layer Security (MLS) Protocol](https://datatracker.ietf.org/doc/rfc9420/) | The group key agreement protocol used by quicproquo. Defines KeyPackages, Welcome messages, Commits, the ratchet tree, epoch advancement, and the security properties (forward secrecy, post-compromise security). See [MLS (RFC 9420)](../protocol-layers/mls.md). |
|
||||
| [RFC 9000 -- QUIC: A UDP-Based Multiplexed and Secure Transport](https://datatracker.ietf.org/doc/rfc9000/) | The transport protocol underlying quicproquo's primary connection layer. Provides multiplexed streams, 0-RTT connection establishment, and built-in congestion control. See [QUIC + TLS 1.3](../protocol-layers/quic-tls.md). |
|
||||
| [RFC 9001 -- Using TLS to Secure QUIC](https://datatracker.ietf.org/doc/rfc9001/) | Defines how TLS 1.3 is integrated into QUIC for authentication and key exchange. quicproquo uses this via the `quinn` + `rustls` stack. |
|
||||
| [RFC 8446 -- The Transport Layer Security (TLS) Protocol Version 1.3](https://datatracker.ietf.org/doc/rfc8446/) | The TLS version used exclusively by quicproquo (no TLS 1.2 fallback). Provides the handshake, key schedule, and record layer for QUIC transport security. |
|
||||
| [RFC 9180 -- Hybrid Public Key Encryption (HPKE)](https://datatracker.ietf.org/doc/rfc9180/) | The public-key encryption scheme used internally by MLS for encrypting to KeyPackage init keys. quicproquo's MLS ciphersuite uses DHKEM(X25519, HKDF-SHA256) with AES-128-GCM. |
|
||||
| [NIST FIPS 203 -- Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM)](https://csrc.nist.gov/pubs/fips/203/final) | The post-quantum KEM standard. quicproquo plans to use ML-KEM-768 in a hybrid construction with X25519 at milestone M7. See [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md). |
|
||||
| [Cap'n Proto specification](https://capnproto.org/) | The zero-copy serialisation format and RPC system used for all quicproquo wire messages and service interfaces. See [Cap'n Proto Serialisation and RPC](../protocol-layers/capn-proto.md). |
|
||||
| [draft-ietf-tls-hybrid-design -- Hybrid Key Exchange in TLS 1.3](https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/) | The combiner approach used by quicproquo's hybrid KEM construction (X25519 shared secret concatenated with ML-KEM-768 shared secret, fed through HKDF). See [Hybrid KEM](../protocol-layers/hybrid-kem.md). |
|
||||
| [RFC 9497 -- OPAQUE](https://datatracker.ietf.org/doc/rfc9497/) | Asymmetric password-authenticated key exchange. Considered for future authentication (see [Future Research](../roadmap/future-research.md)). |
|
||||
|
||||
---
|
||||
|
||||
## Rust Crate Documentation
|
||||
|
||||
| Crate | docs.rs | Role in quicnprotochat |
|
||||
| Crate | docs.rs | Role in quicproquo |
|
||||
|-------|---------|----------------------|
|
||||
| `openmls` | [docs.rs/openmls](https://docs.rs/openmls/) | MLS protocol implementation: group creation, member addition, Welcome processing, application message encryption/decryption. See [MLS (RFC 9420)](../protocol-layers/mls.md). |
|
||||
| `openmls_rust_crypto` | [docs.rs/openmls_rust_crypto](https://docs.rs/openmls_rust_crypto/) | Pure-Rust cryptographic backend for openmls. Provides the `OpenMlsRustCrypto` provider used by `GroupMember`. |
|
||||
@@ -57,7 +57,7 @@ Katriel Cohn-Gordon, Cas Cremers, Luke Garratt, Jon Millican, and Kevin Milner.
|
||||
This paper analyses the security properties of group messaging protocols and
|
||||
motivates the design of MLS. It defines the security goals (forward secrecy,
|
||||
post-compromise security, asynchronous operation) that MLS formalises into a
|
||||
protocol. Essential background for understanding why quicnprotochat uses MLS
|
||||
protocol. Essential background for understanding why quicproquo uses MLS
|
||||
rather than extending the Signal protocol to groups.
|
||||
|
||||
### Signal Protocol
|
||||
@@ -67,7 +67,7 @@ Trevor Perrin and Moxie Marlinspike.
|
||||
[signal.org/docs/specifications/doubleratchet](https://signal.org/docs/specifications/doubleratchet/)
|
||||
|
||||
Defines the double ratchet used in Signal's 1:1 messaging. Relevant as a
|
||||
potential optimisation for quicnprotochat's 1:1 channels (see
|
||||
potential optimisation for quicproquo's 1:1 channels (see
|
||||
[Future Research: Double-Ratchet DM Layer](../roadmap/future-research.md#double-ratchet-dm-layer))
|
||||
and as background for understanding how MLS generalises ratcheting to groups.
|
||||
|
||||
@@ -86,7 +86,7 @@ Roberto Avanzi et al.
|
||||
[NIST PQC Round 3 submission](https://pq-crystals.org/kyber/)
|
||||
|
||||
The predecessor to ML-KEM (NIST FIPS 203). CRYSTALS-Kyber was selected by NIST
|
||||
and standardised as ML-KEM. quicnprotochat uses the `ml-kem` crate which
|
||||
and standardised as ML-KEM. quicproquo uses the `ml-kem` crate which
|
||||
implements the final FIPS 203 standard.
|
||||
|
||||
### Metadata Resistance
|
||||
@@ -96,7 +96,7 @@ Signal Blog.
|
||||
[signal.org/blog/sealed-sender](https://signal.org/blog/sealed-sender/)
|
||||
|
||||
Describes Signal's approach to hiding sender identity from the server. Relevant
|
||||
to quicnprotochat's future research on metadata resistance (see
|
||||
to quicproquo's future research on metadata resistance (see
|
||||
[Future Research](../roadmap/future-research.md)).
|
||||
|
||||
---
|
||||
@@ -104,7 +104,7 @@ to quicnprotochat's future research on metadata resistance (see
|
||||
## Cross-references
|
||||
|
||||
- [Glossary](glossary.md) -- definitions of terms used in these references
|
||||
- [Protocol Layers Overview](../protocol-layers/overview.md) -- how the protocols layer in quicnprotochat
|
||||
- [Protocol Layers Overview](../protocol-layers/overview.md) -- how the protocols layer in quicproquo
|
||||
- [Cryptography Overview](../cryptography/overview.md) -- cryptographic properties and threat model
|
||||
- [Future Research](../roadmap/future-research.md) -- technologies under consideration
|
||||
- [Milestones](../roadmap/milestones.md) -- current project status
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Crate Responsibilities
|
||||
|
||||
The quicnprotochat workspace contains six crates. The main four (proto, core,
|
||||
The quicproquo workspace contains six crates. The main four (proto, core,
|
||||
server, client) follow strict layering rules; each owns one concern and depends
|
||||
only on the crates below it. The workspace also includes **quicnprotochat-gui**
|
||||
(Tauri desktop app) and **quicnprotochat-p2p** (P2P endpoint resolution). This
|
||||
only on the crates below it. The workspace also includes **quicproquo-gui**
|
||||
(Tauri desktop app) and **quicproquo-p2p** (P2P endpoint resolution). This
|
||||
page documents what each crate provides, what it explicitly avoids, and how the
|
||||
crates relate to one another.
|
||||
|
||||
@@ -13,7 +13,7 @@ crates relate to one another.
|
||||
|
||||
```text
|
||||
┌──────────────────────────┐
|
||||
│ quicnprotochat-client │
|
||||
│ quicproquo-client │
|
||||
│ (CLI, QUIC client, │
|
||||
│ GroupMember orchestr.) │
|
||||
└─────────┬───────┬────────┘
|
||||
@@ -21,7 +21,7 @@ crates relate to one another.
|
||||
┌───────┘ └────────┐
|
||||
▼ ▼
|
||||
┌────────────────────────┐ ┌────────────────────────┐
|
||||
│ quicnprotochat-core │ │ quicnprotochat-server │
|
||||
│ quicproquo-core │ │ quicproquo-server │
|
||||
│ (crypto, MLS, │ │ (QUIC listener, │
|
||||
│ hybrid KEM) │ │ NodeService RPC, │
|
||||
│ │ │ storage) │
|
||||
@@ -30,7 +30,7 @@ crates relate to one another.
|
||||
│ ┌───────────────────┘
|
||||
▼ ▼
|
||||
┌────────────────────────┐
|
||||
│ quicnprotochat-proto │
|
||||
│ quicproquo-proto │
|
||||
│ (Cap'n Proto schemas, │
|
||||
│ codegen, helpers) │
|
||||
└────────────────────────┘
|
||||
@@ -42,7 +42,7 @@ serialisation. The server and client crates both depend on core and proto.
|
||||
|
||||
---
|
||||
|
||||
## quicnprotochat-core
|
||||
## quicproquo-core
|
||||
|
||||
**Role:** Pure cryptographic logic. No network I/O. No async runtime
|
||||
dependency.
|
||||
@@ -70,12 +70,12 @@ dependency.
|
||||
|
||||
`ed25519-dalek`, `openmls`, `openmls_rust_crypto`,
|
||||
`openmls_traits`, `tls_codec`, `ml-kem`, `x25519-dalek`, `chacha20poly1305`,
|
||||
`hkdf`, `sha2`, `zeroize`, `capnp`, `quicnprotochat-proto`, `tokio`,
|
||||
`hkdf`, `sha2`, `zeroize`, `capnp`, `quicproquo-proto`, `tokio`,
|
||||
`serde`, `bincode`, `serde_json`, `thiserror`.
|
||||
|
||||
---
|
||||
|
||||
## quicnprotochat-proto
|
||||
## quicproquo-proto
|
||||
|
||||
**Role:** Cap'n Proto schema definitions, compile-time code generation, and
|
||||
pure-synchronous serialisation helpers. This crate is the single source of truth
|
||||
@@ -110,7 +110,7 @@ for the wire format.
|
||||
|
||||
---
|
||||
|
||||
## quicnprotochat-server
|
||||
## quicproquo-server
|
||||
|
||||
**Role:** Network-facing server binary. Accepts QUIC + TLS 1.3 connections,
|
||||
dispatches Cap'n Proto RPC calls to `NodeServiceImpl`, and persists state to
|
||||
@@ -143,19 +143,19 @@ is handled by `spawn_local`.
|
||||
|
||||
### What this crate does NOT do
|
||||
|
||||
- No direct crypto operations (it delegates to `quicnprotochat-core` types
|
||||
- No direct crypto operations (it delegates to `quicproquo-core` types
|
||||
for fingerprinting and storage only).
|
||||
- No MLS processing -- all payloads are opaque byte strings.
|
||||
|
||||
### Key dependencies
|
||||
|
||||
`quicnprotochat-core`, `quicnprotochat-proto`, `quinn`, `quinn-proto`,
|
||||
`quicproquo-core`, `quicproquo-proto`, `quinn`, `quinn-proto`,
|
||||
`rustls`, `rcgen`, `capnp`, `capnp-rpc`, `tokio`, `tokio-util`, `dashmap`,
|
||||
`sha2`, `clap`, `tracing`, `anyhow`, `thiserror`, `bincode`, `serde`.
|
||||
|
||||
---
|
||||
|
||||
## quicnprotochat-client
|
||||
## quicproquo-client
|
||||
|
||||
**Role:** CLI client binary. Connects to the server over QUIC + TLS 1.3,
|
||||
orchestrates MLS group operations via `GroupMember`, and persists identity and
|
||||
@@ -167,7 +167,7 @@ group state to disk.
|
||||
|-------------------------|-------------|
|
||||
| `connect_node` | Establishes a QUIC/TLS connection, opens a bidirectional stream, and bootstraps a `capnp-rpc` `RpcSystem` to obtain a `node_service::Client`. |
|
||||
| CLI subcommands (`clap`)| `ping`, `register`, `fetch-key`, `demo-group`, `register-state`, `create-group`, `invite`, `join`, `send`, `recv`. |
|
||||
| `GroupMember` usage | The client creates a `GroupMember` (from `quicnprotochat-core`), calls `generate_key_package` / `create_group` / `add_member` / `join_group` / `send_message` / `receive_message`. |
|
||||
| `GroupMember` usage | The client creates a `GroupMember` (from `quicproquo-core`), calls `generate_key_package` / `create_group` / `add_member` / `join_group` / `send_message` / `receive_message`. |
|
||||
| State persistence | `StoredState` holds `identity_seed` (32 bytes) and optional serialised `MlsGroup`. A companion `.ks` file stores the `DiskKeyStore` with HPKE init private keys. |
|
||||
| Auth context | `ClientAuth` bundles an optional bearer token and device ID. Passed to every RPC via the `Auth` struct in `node.capnp`. |
|
||||
|
||||
@@ -194,7 +194,7 @@ group state to disk.
|
||||
|
||||
### Key dependencies
|
||||
|
||||
`quicnprotochat-core`, `quicnprotochat-proto`, `quinn`, `quinn-proto`,
|
||||
`quicproquo-core`, `quicproquo-proto`, `quinn`, `quinn-proto`,
|
||||
`rustls`, `capnp`, `capnp-rpc`, `tokio`, `tokio-util`, `clap`, `sha2`,
|
||||
`serde`, `bincode`, `anyhow`, `thiserror`, `tracing`.
|
||||
|
||||
@@ -204,8 +204,8 @@ group state to disk.
|
||||
|
||||
| Crate | Role |
|
||||
|-------------------------|------|
|
||||
| **quicnprotochat-gui** | Tauri 2 desktop application; provides a GUI on top of the client/core stack. |
|
||||
| **quicnprotochat-p2p** | P2P endpoint publish/resolve; used by the server and clients for direct peer discovery. |
|
||||
| **quicproquo-gui** | Tauri 2 desktop application; provides a GUI on top of the client/core stack. |
|
||||
| **quicproquo-p2p** | P2P endpoint publish/resolve; used by the server and clients for direct peer discovery. |
|
||||
|
||||
These crates are optional for building and running the server and CLI client.
|
||||
|
||||
@@ -220,12 +220,12 @@ These crates are optional for building and running the server and CLI client.
|
||||
4. **client** depends on **core** and **proto**. It does not depend on server.
|
||||
5. **server** and **client** never depend on each other. They communicate
|
||||
exclusively via the Cap'n Proto RPC wire protocol.
|
||||
6. **quicnprotochat-gui** and **quicnprotochat-p2p** are optional; they depend
|
||||
6. **quicproquo-gui** and **quicproquo-p2p** are optional; they depend
|
||||
on client/core/proto as needed and do not change the core layering.
|
||||
|
||||
This layering ensures that:
|
||||
|
||||
- Crypto code can be tested in isolation (`cargo test -p quicnprotochat-core`).
|
||||
- Crypto code can be tested in isolation (`cargo test -p quicproquo-core`).
|
||||
- Schema changes propagate automatically through codegen.
|
||||
- The server binary contains no client-side MLS orchestration logic.
|
||||
- The client binary contains no server-side storage or listener logic.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# End-to-End Data Flow
|
||||
|
||||
This page traces the three core data flows through the quicnprotochat system:
|
||||
This page traces the three core data flows through the quicproquo system:
|
||||
registration, group creation, and message exchange. Each flow is illustrated
|
||||
with an ASCII sequence diagram showing control-plane (AS) and data-plane (DS)
|
||||
traffic.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Architecture Overview
|
||||
|
||||
quicnprotochat is an end-to-end encrypted group messaging system built in Rust.
|
||||
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.
|
||||
|
||||
@@ -28,11 +28,11 @@ connection lifecycle, and the long-polling `fetchWait` mechanism.
|
||||
|
||||
## Identity Key Model
|
||||
|
||||
Each quicnprotochat client holds a single Ed25519 signing keypair that serves
|
||||
Each quicproquo client holds a single Ed25519 signing keypair that serves
|
||||
as its long-term identity:
|
||||
|
||||
```text
|
||||
quicnprotochat Key Model
|
||||
quicproquo Key Model
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Ed25519 signing keypair (MLS identity) │
|
||||
@@ -135,10 +135,10 @@ The implementation is split across four workspace crates:
|
||||
|
||||
| Crate | Role |
|
||||
|----------------------------|-------------------------------------------------------------------|
|
||||
| `quicnprotochat-core` | Crypto primitives, 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 |
|
||||
| `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](crate-responsibilities.md) for a full breakdown
|
||||
and dependency diagram.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Protocol Stack
|
||||
|
||||
quicnprotochat layers three protocol stages to move a plaintext message from
|
||||
quicproquo layers three protocol stages to move a plaintext message from
|
||||
sender to recipient with end-to-end encryption, typed RPC framing, and
|
||||
authenticated transport. This page describes each layer and provides a
|
||||
comparison table.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Service Architecture
|
||||
|
||||
The quicnprotochat server exposes a single **NodeService** RPC endpoint that
|
||||
The quicproquo server exposes a single **NodeService** RPC endpoint that
|
||||
combines Authentication and Delivery operations. This page documents the RPC
|
||||
interface, per-connection lifecycle, storage model, long-polling mechanism, and
|
||||
authentication context.
|
||||
@@ -234,10 +234,10 @@ The server binary is configured via CLI flags or environment variables:
|
||||
|
||||
| Flag | Env var | Default | Description |
|
||||
|----------------|----------------------------|----------------------|-------------|
|
||||
| `--listen` | `QUICNPROTOCHAT_LISTEN` | `0.0.0.0:7000` | QUIC listen address (host:port). |
|
||||
| `--data-dir` | `QUICNPROTOCHAT_DATA_DIR` | `data` | Directory for persisted KeyPackages, delivery queues, and hybrid keys. |
|
||||
| `--tls-cert` | `QUICNPROTOCHAT_TLS_CERT` | `data/server-cert.der` | Path to TLS certificate (DER). Auto-generated if missing. |
|
||||
| `--tls-key` | `QUICNPROTOCHAT_TLS_KEY` | `data/server-key.der` | Path to TLS private key (DER). Auto-generated if missing. |
|
||||
| `--listen` | `QPQ_LISTEN` | `0.0.0.0:7000` | QUIC listen address (host:port). |
|
||||
| `--data-dir` | `QPQ_DATA_DIR` | `data` | Directory for persisted KeyPackages, delivery queues, and hybrid keys. |
|
||||
| `--tls-cert` | `QPQ_TLS_CERT` | `data/server-cert.der` | Path to TLS certificate (DER). Auto-generated if missing. |
|
||||
| `--tls-key` | `QPQ_TLS_KEY` | `data/server-key.der` | Path to TLS private key (DER). Auto-generated if missing. |
|
||||
|
||||
If the TLS certificate or key files do not exist at startup, the server
|
||||
auto-generates a self-signed certificate for `localhost`, `127.0.0.1`, and
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Coding Standards
|
||||
|
||||
This page defines the engineering standards for quicnprotochat. These are
|
||||
This page defines the engineering standards for quicproquo. These are
|
||||
non-negotiable -- all code merged into the repository must conform to these
|
||||
rules. The standards exist to ensure that every milestone produces
|
||||
production-ready, auditable, and secure code.
|
||||
@@ -86,9 +86,9 @@ pub fn create_group(
|
||||
|
||||
- No `unwrap()` or `expect()` on cryptographic operations. All crypto errors
|
||||
must be typed and propagated.
|
||||
- Use `thiserror` for library error types (`quicnprotochat-core`,
|
||||
`quicnprotochat-proto`) and `anyhow` for application-level error handling
|
||||
(`quicnprotochat-server`, `quicnprotochat-client`).
|
||||
- Use `thiserror` for library error types (`quicproquo-core`,
|
||||
`quicproquo-proto`) and `anyhow` for application-level error handling
|
||||
(`quicproquo-server`, `quicproquo-client`).
|
||||
- `unwrap()` is acceptable only in:
|
||||
- Test code.
|
||||
- Cases where the invariant is provably guaranteed by the type system
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Testing Strategy
|
||||
|
||||
This page describes the testing structure, conventions, and current coverage for
|
||||
quicnprotochat. All tests run with `cargo test --workspace` and must pass before
|
||||
quicproquo. All tests run with `cargo test --workspace` and must pass before
|
||||
any code is merged.
|
||||
|
||||
For the coding standards that tests must follow, see
|
||||
@@ -17,7 +17,7 @@ Unit tests live alongside the code they test, in `#[cfg(test)] mod tests` blocks
|
||||
at the bottom of each source file. They test individual functions and types in
|
||||
isolation.
|
||||
|
||||
**quicnprotochat-core:**
|
||||
**quicproquo-core:**
|
||||
|
||||
| Module | Tests | What they cover |
|
||||
|--------|-------|----------------|
|
||||
@@ -26,7 +26,7 @@ isolation.
|
||||
| `group` | 2 tests | Group round-trip (create + add + join + send + recv), group\_id lifecycle |
|
||||
| `hybrid_kem` | 11 tests | Encapsulate/decapsulate round-trip, key generation, combiner correctness, wrong-key rejection, serialisation |
|
||||
|
||||
**quicnprotochat-proto:**
|
||||
**quicproquo-proto:**
|
||||
|
||||
| Module | Tests | What they cover |
|
||||
|--------|-------|----------------|
|
||||
@@ -34,7 +34,7 @@ isolation.
|
||||
|
||||
### Integration Tests
|
||||
|
||||
Integration tests live in `crates/quicnprotochat-client/tests/` and test the
|
||||
Integration tests live in `crates/quicproquo-client/tests/` and test the
|
||||
full client-server interaction. Each test spawns a server using `tokio::spawn`
|
||||
within the same test binary, then runs client operations against it.
|
||||
|
||||
@@ -88,17 +88,17 @@ This runs all unit tests and integration tests across all four crates.
|
||||
### Single Crate
|
||||
|
||||
```bash
|
||||
cargo test -p quicnprotochat-core
|
||||
cargo test -p quicnprotochat-proto
|
||||
cargo test -p quicnprotochat-server
|
||||
cargo test -p quicnprotochat-client
|
||||
cargo test -p quicproquo-core
|
||||
cargo test -p quicproquo-proto
|
||||
cargo test -p quicproquo-server
|
||||
cargo test -p quicproquo-client
|
||||
```
|
||||
|
||||
### Single Test
|
||||
|
||||
```bash
|
||||
cargo test -p quicnprotochat-core -- codec::tests::test_round_trip
|
||||
cargo test -p quicnprotochat-client --test mls_group
|
||||
cargo test -p quicproquo-core -- codec::tests::test_round_trip
|
||||
cargo test -p quicproquo-client --test mls_group
|
||||
```
|
||||
|
||||
### With Output
|
||||
@@ -117,10 +117,10 @@ Summary:
|
||||
|
||||
| Crate | Unit Tests | Integration Tests | Total |
|
||||
|-------|-----------|-------------------|-------|
|
||||
| `quicnprotochat-core` | 23 | -- | 23 |
|
||||
| `quicnprotochat-proto` | 3 | -- | 3 |
|
||||
| `quicnprotochat-server` | 0 | -- | 0 |
|
||||
| `quicnprotochat-client` | 0 | 5 | 5 |
|
||||
| `quicproquo-core` | 23 | -- | 23 |
|
||||
| `quicproquo-proto` | 3 | -- | 3 |
|
||||
| `quicproquo-server` | 0 | -- | 0 |
|
||||
| `quicproquo-client` | 0 | 5 | 5 |
|
||||
| **Total** | **26** | **5** | **31** |
|
||||
|
||||
---
|
||||
|
||||
@@ -6,7 +6,7 @@ compromised, past session keys cannot be recovered.** In other words, an
|
||||
attacker who obtains today's long-term key cannot use it to decrypt messages
|
||||
recorded yesterday.
|
||||
|
||||
quicnprotochat provides forward secrecy at two independent layers: the transport
|
||||
quicproquo provides forward secrecy at two independent layers: the transport
|
||||
layer and the application layer. Even if one layer's FS mechanism is defeated,
|
||||
the other continues to protect message confidentiality.
|
||||
|
||||
@@ -28,7 +28,7 @@ In each TLS 1.3 handshake:
|
||||
|
||||
Because the ephemeral keys exist only for the duration of the handshake,
|
||||
compromising the server's long-term TLS certificate key (currently self-signed
|
||||
in quicnprotochat) does not reveal past session keys.
|
||||
in quicproquo) does not reveal past session keys.
|
||||
|
||||
## Application Layer Forward Secrecy
|
||||
|
||||
@@ -54,7 +54,7 @@ This deletion is the mechanism that provides forward secrecy: once old epoch
|
||||
keys are erased, messages encrypted under those keys cannot be decrypted, even
|
||||
if the current group state is compromised.
|
||||
|
||||
In quicnprotochat, epoch advancement occurs when:
|
||||
In quicproquo, epoch advancement occurs when:
|
||||
|
||||
- `add_member()` is called, which creates a Commit and calls
|
||||
`merge_pending_commit()`.
|
||||
@@ -91,7 +91,7 @@ HPKE init keys.
|
||||
|
||||
## Layered Forward Secrecy
|
||||
|
||||
A distinctive property of quicnprotochat's design is that forward secrecy
|
||||
A distinctive property of quicproquo's design is that forward secrecy
|
||||
operates at two independent layers:
|
||||
|
||||
```text
|
||||
@@ -135,7 +135,7 @@ unless they also break the transport encryption.
|
||||
Signal's Double Ratchet protocol also provides forward secrecy, but the
|
||||
mechanisms differ:
|
||||
|
||||
| Property | Signal Double Ratchet | MLS (quicnprotochat) |
|
||||
| Property | Signal Double Ratchet | MLS (quicproquo) |
|
||||
|----------|----------------------|---------------------|
|
||||
| Scope | Pairwise (1:1 sessions) | Group (n-party) |
|
||||
| Ratchet granularity | Per message (symmetric ratchet) + per DH round (DH ratchet) | Per epoch (Commit) |
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Ed25519 Identity Keys
|
||||
|
||||
The Ed25519 identity keypair is the long-term cryptographic identity of a
|
||||
quicnprotochat client. It is generated once, persisted across sessions, and used
|
||||
quicproquo client. It is generated once, persisted across sessions, and used
|
||||
for MLS credential signing, Authentication Service registration, and delivery
|
||||
queue addressing.
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/identity.rs`
|
||||
**Source:** `crates/quicproquo-core/src/identity.rs`
|
||||
|
||||
## Structure
|
||||
|
||||
@@ -37,7 +37,7 @@ A fresh identity keypair is generated from the OS CSPRNG (`OsRng`) via
|
||||
`ed25519-dalek`:
|
||||
|
||||
```rust
|
||||
use quicnprotochat_core::identity::IdentityKeypair;
|
||||
use quicproquo_core::identity::IdentityKeypair;
|
||||
|
||||
let identity = IdentityKeypair::generate();
|
||||
// The signing key seed is generated from OsRng (getrandom on Linux).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Key Lifecycle and Zeroization
|
||||
|
||||
quicnprotochat uses multiple key types with different lifetimes, creation
|
||||
quicproquo uses multiple key types with different lifetimes, creation
|
||||
patterns, and destruction guarantees. This page provides a comprehensive
|
||||
lifecycle diagram for every key type in the system, from generation through
|
||||
zeroization.
|
||||
@@ -25,7 +25,7 @@ Hybrid KEM Keys Per peer (future) Public portion X25519+ML-KEM-768
|
||||
|
||||
## Ed25519 Identity Key
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/identity.rs`
|
||||
**Source:** `crates/quicproquo-core/src/identity.rs`
|
||||
|
||||
The Ed25519 identity key is the most long-lived secret in the system. It
|
||||
represents the client's cryptographic identity across all sessions and groups.
|
||||
@@ -92,8 +92,8 @@ zeroization.
|
||||
|
||||
## HPKE Init Keys
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/keystore.rs` and
|
||||
`crates/quicnprotochat-core/src/group.rs`
|
||||
**Source:** `crates/quicproquo-core/src/keystore.rs` and
|
||||
`crates/quicproquo-core/src/group.rs`
|
||||
|
||||
HPKE init keys are generated by the openmls backend as part of MLS KeyPackage
|
||||
creation. They are single-use: each init key is consumed exactly once when
|
||||
@@ -167,7 +167,7 @@ processing a Welcome message.
|
||||
**Managed by:** `openmls` (internal to the `MlsGroup` state machine)
|
||||
|
||||
MLS epoch keys are derived internally by the openmls ratchet tree. They are not
|
||||
directly accessible in quicnprotochat code but are critical to understanding the
|
||||
directly accessible in quicproquo code but are critical to understanding the
|
||||
system's security properties.
|
||||
|
||||
### Lifecycle
|
||||
@@ -216,12 +216,12 @@ system's security properties.
|
||||
- **Deletion:** Old epoch keys are deleted after the Commit is processed. This
|
||||
deletion is what provides [forward secrecy](forward-secrecy.md) at the MLS
|
||||
layer.
|
||||
- **No direct access:** quicnprotochat code interacts with epoch keys only
|
||||
- **No direct access:** quicproquo code interacts with epoch keys only
|
||||
indirectly through `send_message()` and `receive_message()`.
|
||||
|
||||
## Hybrid KEM Keys (Future -- M5+)
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/hybrid_kem.rs`
|
||||
**Source:** `crates/quicproquo-core/src/hybrid_kem.rs`
|
||||
|
||||
The hybrid KEM keypair combines X25519 (classical) with ML-KEM-768
|
||||
(post-quantum) for content encryption that resists both classical and quantum
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Cryptography Overview
|
||||
|
||||
quicnprotochat layers multiple cryptographic protocols to provide confidentiality,
|
||||
quicproquo layers multiple cryptographic protocols to provide confidentiality,
|
||||
integrity, authentication, forward secrecy, and post-compromise security. This
|
||||
page catalogues every algorithm in the system, the crate that supplies it, and
|
||||
the security margin it provides.
|
||||
|
||||
@@ -13,7 +13,7 @@ PCS is the complement of [forward secrecy](forward-secrecy.md):
|
||||
- **Post-compromise security** protects the **future** from a past compromise.
|
||||
|
||||
MLS (RFC 9420) is specifically designed to provide both properties simultaneously
|
||||
for group messaging. This is a key differentiator of quicnprotochat's design.
|
||||
for group messaging. This is a key differentiator of quicproquo's design.
|
||||
|
||||
## How MLS Provides PCS
|
||||
|
||||
@@ -64,7 +64,7 @@ This means:
|
||||
For a group of 1,000 members, the path length is approximately 10 nodes --
|
||||
making PCS practical even for large groups.
|
||||
|
||||
## Epoch Advancement in quicnprotochat
|
||||
## Epoch Advancement in quicproquo
|
||||
|
||||
In the current implementation, epoch advancement occurs through the `GroupMember`
|
||||
methods in `group.rs`:
|
||||
@@ -145,7 +145,7 @@ deleted), and future epochs are protected by PCS (new key material generated).
|
||||
|
||||
Signal's group messaging uses **Sender Keys**, a fundamentally different
|
||||
mechanism from MLS's ratchet tree. The comparison is instructive because it
|
||||
highlights why MLS was chosen for quicnprotochat:
|
||||
highlights why MLS was chosen for quicproquo:
|
||||
|
||||
### Signal Sender Keys
|
||||
|
||||
@@ -168,7 +168,7 @@ security. If an attacker compromises a member's Sender Key:
|
||||
membership changes.
|
||||
- There is no automatic healing mechanism analogous to MLS's ratchet tree.
|
||||
|
||||
### MLS Ratchet Tree (quicnprotochat)
|
||||
### MLS Ratchet Tree (quicproquo)
|
||||
|
||||
In contrast, MLS's ratchet tree provides PCS because:
|
||||
|
||||
@@ -218,7 +218,7 @@ periodic Updates (planned) will bound the healing window.
|
||||
|
||||
### Server compromise does not prevent PCS
|
||||
|
||||
The quicnprotochat server is MLS-unaware -- it stores and forwards encrypted
|
||||
The quicproquo server is MLS-unaware -- it stores and forwards encrypted
|
||||
MLS messages without access to the group state. A compromised server cannot:
|
||||
|
||||
- Prevent PCS by blocking Commits (it could perform denial-of-service, but
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# Post-Quantum Readiness
|
||||
|
||||
quicnprotochat includes a fully implemented and tested hybrid key encapsulation
|
||||
quicproquo includes a fully implemented and tested hybrid key encapsulation
|
||||
mechanism (KEM) combining X25519 (classical) with ML-KEM-768 (post-quantum).
|
||||
This page describes the current implementation, the integration plan, the
|
||||
security rationale, and the known gaps.
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/hybrid_kem.rs`
|
||||
**Source:** `crates/quicproquo-core/src/hybrid_kem.rs`
|
||||
|
||||
## Current State
|
||||
|
||||
The hybrid KEM is **fully implemented and tested** in `quicnprotochat-core`. The
|
||||
The hybrid KEM is **fully implemented and tested** in `quicproquo-core`. The
|
||||
implementation provides:
|
||||
|
||||
- `HybridKeypair::generate()` -- generate a combined X25519 + ML-KEM-768 keypair
|
||||
@@ -35,7 +35,7 @@ The test suite in `hybrid_kem.rs` includes 10 tests covering:
|
||||
## ML-KEM-768 (FIPS 203)
|
||||
|
||||
ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism) is the NIST-standardized
|
||||
post-quantum KEM, published as FIPS 203. quicnprotochat uses ML-KEM-768, the
|
||||
post-quantum KEM, published as FIPS 203. quicproquo uses ML-KEM-768, the
|
||||
middle parameter set:
|
||||
|
||||
| Parameter Set | NIST Level | Security (PQ) | EK Size | CT Size | SS Size |
|
||||
@@ -69,8 +69,8 @@ executed, and their shared secrets are combined through a KDF:
|
||||
|
||||
```text
|
||||
ikm = X25519_shared_secret(32 bytes) || ML-KEM_shared_secret(32 bytes)
|
||||
key = HKDF-SHA256(salt=[], ikm, info="quicnprotochat-hybrid-v1", L=32)
|
||||
nonce = HKDF-SHA256(salt=[], ikm, info="quicnprotochat-hybrid-nonce-v1", L=12)
|
||||
key = HKDF-SHA256(salt=[], ikm, info="quicproquo-hybrid-v1", L=32)
|
||||
nonce = HKDF-SHA256(salt=[], ikm, info="quicproquo-hybrid-nonce-v1", L=12)
|
||||
```
|
||||
|
||||
The combined IKM (input key material) is wrapped in `Zeroizing<Vec<u8>>` and
|
||||
@@ -165,7 +165,7 @@ hybrid KEM for HPKE init key exchange:
|
||||
|
||||
## The PQ Gap
|
||||
|
||||
There is an important asymmetry in quicnprotochat's post-quantum protection:
|
||||
There is an important asymmetry in quicproquo's post-quantum protection:
|
||||
|
||||
```text
|
||||
Layer Classical Protection Post-Quantum Protection
|
||||
@@ -191,7 +191,7 @@ This is the **PQ gap**: content is safe, but metadata is not.
|
||||
|
||||
Post-quantum TLS (via ML-KEM in the TLS 1.3 handshake) is being standardized by
|
||||
the IETF and is supported by some TLS libraries, but `rustls` does not yet
|
||||
support it in a stable release. When `rustls` adds ML-KEM support, quicnprotochat
|
||||
support it in a stable release. When `rustls` adds ML-KEM support, quicproquo
|
||||
will adopt it to close the PQ gap at the transport layer.
|
||||
|
||||
## Harvest-Now, Decrypt-Later Risk
|
||||
@@ -202,7 +202,7 @@ The "harvest-now, decrypt-later" (HNDL) threat model assumes an adversary who:
|
||||
2. Waits for a sufficiently powerful quantum computer (years or decades).
|
||||
3. Decrypts the recorded traffic retroactively.
|
||||
|
||||
In quicnprotochat's case:
|
||||
In quicproquo's case:
|
||||
|
||||
- **Content is safe from M5 onward.** The hybrid KEM wrapping MLS content uses
|
||||
ML-KEM-768, which resists quantum attacks. Even if the recorded traffic is
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Threat Model
|
||||
|
||||
This page defines the attacker models quicnprotochat is designed to resist,
|
||||
This page defines the attacker models quicproquo is designed to resist,
|
||||
catalogues what is and is not protected, identifies known gaps in the current
|
||||
implementation, and outlines future mitigations.
|
||||
|
||||
@@ -41,7 +41,7 @@ state-level adversary).
|
||||
**What they can do:**
|
||||
|
||||
- Attempt TLS 1.3 MITM: TLS 1.3 prevents this if the client validates the
|
||||
server's certificate. However, quicnprotochat currently uses **self-signed
|
||||
server's certificate. However, quicproquo currently uses **self-signed
|
||||
certificates**, which means the client has no CA chain to verify. On the first
|
||||
connection, a MITM could present their own certificate and intercept the
|
||||
session (trust-on-first-use vulnerability).
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## Context
|
||||
|
||||
quicnprotochat needs an efficient, typed wire format for client-server communication. The format must support:
|
||||
quicproquo needs an efficient, typed wire format for client-server communication. The format must support:
|
||||
|
||||
1. **Typed messages** with compile-time schema enforcement to eliminate hand-rolled serialisation bugs.
|
||||
2. **Schema evolution** so that new fields and methods can be added without breaking existing clients.
|
||||
@@ -105,7 +105,7 @@ The Cap'n Proto schemas are stored in the `schemas/` directory:
|
||||
|
||||
### Costs and trade-offs
|
||||
|
||||
- **Build-time code generation.** The `capnpc` compiler must run during the build (via `build.rs` in `quicnprotochat-proto`). This adds a build dependency and increases compile times slightly.
|
||||
- **Build-time code generation.** The `capnpc` compiler must run during the build (via `build.rs` in `quicproquo-proto`). This adds a build dependency and increases compile times slightly.
|
||||
- **Learning curve.** Cap'n Proto's builder/reader API is different from typical `serde`-based Rust serialisation. Developers must learn the Cap'n Proto programming model (builders for construction, readers for traversal, owned messages for storage).
|
||||
- **Generated code verbosity.** The generated Rust code is verbose and not intended to be read directly. Application code interacts with it through the builder/reader traits.
|
||||
- **Smaller ecosystem than Protobuf.** Cap'n Proto has fewer users, fewer tutorials, and fewer third-party tools than Protobuf. However, the core Rust crates are well-maintained.
|
||||
@@ -114,7 +114,7 @@ The Cap'n Proto schemas are stored in the `schemas/` directory:
|
||||
### Residual risks
|
||||
|
||||
- **Crate maintenance.** The `capnp` and `capnp-rpc` crates are maintained primarily by David Renshaw. If maintenance lapses, the project would need to fork or switch serialisation formats. Mitigated by the crates' maturity and the relatively stable Cap'n Proto specification.
|
||||
- **RPC limitations.** The Rust `capnp-rpc` crate implements Level 1 of the Cap'n Proto RPC protocol. Level 3 features (three-party handoffs) are not supported. This has not been a limitation for quicnprotochat's client-server architecture.
|
||||
- **RPC limitations.** The Rust `capnp-rpc` crate implements Level 1 of the Cap'n Proto RPC protocol. Level 3 features (three-party handoffs) are not supported. This has not been a limitation for quicproquo's client-server architecture.
|
||||
|
||||
---
|
||||
|
||||
@@ -126,8 +126,8 @@ The Cap'n Proto schemas are stored in the `schemas/` directory:
|
||||
| `schemas/auth.capnp` | AuthenticationService RPC interface |
|
||||
| `schemas/delivery.capnp` | DeliveryService RPC interface |
|
||||
| `schemas/node.capnp` | NodeService unified RPC interface |
|
||||
| `crates/quicnprotochat-proto/build.rs` | Build script that invokes `capnpc` for code generation |
|
||||
| `crates/quicnprotochat-proto/src/lib.rs` | Re-exports generated Cap'n Proto modules |
|
||||
| `crates/quicproquo-proto/build.rs` | Build script that invokes `capnpc` for code generation |
|
||||
| `crates/quicproquo-proto/src/lib.rs` | Re-exports generated Cap'n Proto modules |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ The RFC explicitly envisions that the DS operates on opaque blobs, not on decryp
|
||||
|
||||
## Decision
|
||||
|
||||
The quicnprotochat Delivery Service is **MLS-unaware**. It routes opaque byte strings by `(recipientKey, channelId)` without parsing, inspecting, or validating any MLS content.
|
||||
The quicproquo Delivery Service is **MLS-unaware**. It routes opaque byte strings by `(recipientKey, channelId)` without parsing, inspecting, or validating any MLS content.
|
||||
|
||||
### What the DS sees
|
||||
|
||||
@@ -109,8 +109,8 @@ This means that sending a message to a group of n members requires n-1 enqueue c
|
||||
|---|---|
|
||||
| `schemas/delivery.capnp` | DeliveryService RPC interface (opaque `Data` payloads) |
|
||||
| `schemas/node.capnp` | NodeService: `enqueue`, `fetch`, `fetchWait` methods |
|
||||
| `crates/quicnprotochat-server/src/storage.rs` | Server-side queue storage (DashMap-based FIFO queues) |
|
||||
| `crates/quicnprotochat-server/src/main.rs` | NodeService RPC handler implementation |
|
||||
| `crates/quicproquo-server/src/storage.rs` | Server-side queue storage (DashMap-based FIFO queues) |
|
||||
| `crates/quicproquo-server/src/main.rs` | NodeService RPC handler implementation |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -100,8 +100,8 @@ This is a defense-in-depth measure. In practice, MLS's own signature verificatio
|
||||
|---|---|
|
||||
| `schemas/auth.capnp` | `AuthenticationService` interface: `uploadKeyPackage`, `fetchKeyPackage` |
|
||||
| `schemas/node.capnp` | `NodeService` interface: same methods with `Auth` parameter |
|
||||
| `crates/quicnprotochat-server/src/storage.rs` | Server-side KeyPackage storage (DashMap-backed queue) |
|
||||
| `crates/quicnprotochat-server/src/main.rs` | RPC handler: `fetchKeyPackage` implementation with atomic removal |
|
||||
| `crates/quicproquo-server/src/storage.rs` | Server-side KeyPackage storage (DashMap-backed queue) |
|
||||
| `crates/quicproquo-server/src/main.rs` | RPC handler: `fetchKeyPackage` implementation with atomic removal |
|
||||
|
||||
---
|
||||
|
||||
|
||||
116
docs/src/design-rationale/adr-006-rest-gateway.md
Normal file
116
docs/src/design-rationale/adr-006-rest-gateway.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# ADR-006: SDK-First Adoption — Native QUIC + Cap'n Proto, No REST Gateway
|
||||
|
||||
## Status
|
||||
|
||||
Accepted (supersedes earlier REST gateway proposal)
|
||||
|
||||
## Context
|
||||
|
||||
quicproquo uses QUIC + Cap'n Proto RPC as its native protocol. This
|
||||
combination delivers zero-copy serialization, multiplexed streams, and
|
||||
sub-RTT connection establishment — ideal for high-performance clients.
|
||||
|
||||
Cap'n Proto has limited language support compared to Protocol Buffers or
|
||||
JSON. Adding an HTTP/JSON REST gateway was considered to lower the barrier
|
||||
to entry. However, this would:
|
||||
|
||||
1. **Contradict the project identity.** The name is literally
|
||||
**quic**n**proto**chat. An HTTP gateway undermines the protocol-native
|
||||
philosophy.
|
||||
2. **Add base64 overhead (~33%)** for binary payloads (MLS ciphertext, key
|
||||
packages) that are already optimal in Cap'n Proto's wire format.
|
||||
3. **Create a second code path** to maintain, test, and secure.
|
||||
4. **Lose QUIC transport benefits** (0-RTT, multiplexing, congestion control)
|
||||
for clients that use the HTTP path.
|
||||
|
||||
## Decision
|
||||
|
||||
**No REST/HTTP gateway.** Instead, invest in native QUIC + Cap'n Proto
|
||||
SDKs for every viable language, plus WASM/FFI for the crypto layer.
|
||||
|
||||
The `.capnp` schema files ARE the interface definition — they serve the
|
||||
same role as an OpenAPI spec, but for the native protocol.
|
||||
|
||||
### SDK strategy
|
||||
|
||||
| Language | QUIC | Cap'n Proto | Approach |
|
||||
|----------|------|-------------|----------|
|
||||
| **Rust** | quinn | capnp-rpc | Existing reference client |
|
||||
| **Go** | quic-go | go-capnp | Native SDK, high confidence |
|
||||
| **Python** | aioquic | pycapnp | Native QUIC, manual RPC framing |
|
||||
| **C/C++** | msquic/ngtcp2 | capnproto | Reference impl, full RPC |
|
||||
| **Browser** | WebTransport | WASM bridge | QUIC transport via HTTP/3 |
|
||||
|
||||
### Browser access via WebTransport
|
||||
|
||||
Browsers cannot open raw QUIC connections, but they can use
|
||||
**WebTransport** — which runs over HTTP/3 (which runs over QUIC). The
|
||||
server adds a WebTransport listener alongside the Cap'n Proto QUIC
|
||||
listener. Cap'n Proto RPC is framed over WebTransport bidirectional
|
||||
streams, identical to the native path.
|
||||
|
||||
```
|
||||
Browser → WebTransport (HTTP/3 over QUIC) → Cap'n Proto RPC → Server
|
||||
Native → QUIC → Cap'n Proto RPC → Server
|
||||
```
|
||||
|
||||
Both paths use QUIC transport. The project name stays honest.
|
||||
|
||||
### Crypto layer distribution
|
||||
|
||||
MLS encryption/decryption must happen client-side. The `quicproquo-core`
|
||||
crate is compiled to:
|
||||
|
||||
- **WASM** — for browsers, Node.js, Deno
|
||||
- **C FFI** (`libquicproquo`) — for Swift, Kotlin, Python, Go (via cgo)
|
||||
- **Native Rust** — for Rust clients (existing)
|
||||
|
||||
### Why not REST?
|
||||
|
||||
1. **Protocol purity.** One protocol, one code path, one mental model.
|
||||
2. **No serialization tax.** No base64, no JSON parsing, no HTTP headers.
|
||||
3. **QUIC everywhere.** WebTransport gives browsers QUIC access without HTTP
|
||||
semantics leaking into the protocol.
|
||||
4. **Schema-driven.** `.capnp` files generate type-safe stubs in every
|
||||
supported language — the same developer experience as protobuf/gRPC.
|
||||
|
||||
### Why not gRPC?
|
||||
|
||||
1. **We already have Cap'n Proto** with zero-copy deserialization.
|
||||
2. Adding protobuf would mean three serialization formats in one project.
|
||||
3. Cap'n Proto's time-travel RPC (promise pipelining) is architecturally
|
||||
superior to gRPC's request-response model for chained operations.
|
||||
|
||||
gRPC may be reconsidered for server-to-server federation (Phase 7.3).
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- **Protocol coherence.** Every client speaks the same wire format.
|
||||
- **Performance.** No translation layer, no base64 overhead, no HTTP framing.
|
||||
- **Identity.** The project name accurately describes the protocol stack.
|
||||
- **Security.** One code path to audit, not two.
|
||||
- **WebTransport.** Browsers get native QUIC with the same RPC interface.
|
||||
|
||||
### Negative
|
||||
|
||||
- **Higher SDK effort.** Each language needs a QUIC + Cap'n Proto
|
||||
integration, not just an HTTP client.
|
||||
- **Cap'n Proto ecosystem gaps.** JavaScript and Swift lack mature Cap'n
|
||||
Proto RPC libraries; these languages rely on WASM bridges.
|
||||
- **WebTransport maturity.** Browser support is good (Chrome, Edge, Firefox)
|
||||
but not universal; Safari support is emerging.
|
||||
|
||||
### Neutral
|
||||
|
||||
- SDKs live in separate repositories (e.g., `quicproquo-go`,
|
||||
`quicproquo-py`) to avoid bloating the core workspace.
|
||||
- The C FFI crate (`quicproquo-ffi`) bundles both crypto and transport,
|
||||
so language bindings only need to call C functions.
|
||||
|
||||
## Related
|
||||
|
||||
- [ADR-002: Cap'n Proto over MessagePack](adr-002-capnproto.md) — why Cap'n Proto was chosen
|
||||
- [ROADMAP Phase 3](../../../ROADMAP.md) — SDK implementation plan
|
||||
- [FUTURE-IMPROVEMENTS § 6.2](../../../docs/FUTURE-IMPROVEMENTS.md) — WebTransport research
|
||||
@@ -1,6 +1,6 @@
|
||||
# Design Decisions Overview
|
||||
|
||||
This section collects the Architecture Decision Records (ADRs) that document the key design choices in quicnprotochat. Each ADR follows a standard format: context (why the decision was needed), decision (what was chosen), and consequences (trade-offs, benefits, and residual risks).
|
||||
This section collects the Architecture Decision Records (ADRs) that document the key design choices in quicproquo. Each ADR follows a standard format: context (why the decision was needed), decision (what was chosen), and consequences (trade-offs, benefits, and residual risks).
|
||||
|
||||
These decisions are not immutable. Each ADR has a status field and can be superseded by a later ADR if circumstances change. The goal is to preserve the reasoning behind each choice so that future contributors understand *why* the system works the way it does, not just *how*.
|
||||
|
||||
@@ -18,7 +18,7 @@ These decisions are not immutable. Each ADR has a status field and can be supers
|
||||
|
||||
## Design comparison
|
||||
|
||||
For a broader comparison of quicnprotochat's design against alternative messaging protocols (Signal, Matrix/Olm/Megolm), see [Why This Design, Not Signal/Matrix/...](why-not-signal.md).
|
||||
For a broader comparison of quicproquo's design against alternative messaging protocols (Signal, Matrix/Olm/Megolm), see [Why This Design, Not Signal/Matrix/...](why-not-signal.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Comparison with Classical Chat Protocols
|
||||
|
||||
This page compares quicnprotochat against **classical and legacy chat protocols** -- IRC+SSL, XMPP (with and without OMEMO), Telegram's MTProto, and plain TCP/TLS chat systems -- to demonstrate what a modern, cryptographically rigorous design provides over protocols that were designed before end-to-end encryption, post-compromise security, and post-quantum readiness were practical concerns.
|
||||
This page compares quicproquo against **classical and legacy chat protocols** -- IRC+SSL, XMPP (with and without OMEMO), Telegram's MTProto, and plain TCP/TLS chat systems -- to demonstrate what a modern, cryptographically rigorous design provides over protocols that were designed before end-to-end encryption, post-compromise security, and post-quantum readiness were practical concerns.
|
||||
|
||||
For a comparison against modern E2E-encrypted protocols (Signal, Matrix/Olm/Megolm), see [Why This Design, Not Signal/Matrix/...](why-not-signal.md).
|
||||
|
||||
@@ -9,7 +9,7 @@ For a comparison against modern E2E-encrypted protocols (Signal, Matrix/Olm/Mego
|
||||
## At a glance
|
||||
|
||||
```
|
||||
Classical IRC+SSL quicnprotochat
|
||||
Classical IRC+SSL quicproquo
|
||||
───────────────── ──────────────
|
||||
|
||||
You ──TLS──▶ Server ──TLS──▶ Bob You ──QUIC/TLS──▶ Server ──QUIC/TLS──▶ Bob
|
||||
@@ -19,13 +19,13 @@ For a comparison against modern E2E-encrypted protocols (Signal, Matrix/Olm/Mego
|
||||
messages (cannot decrypt)
|
||||
```
|
||||
|
||||
The fundamental difference: **classical protocols trust the server with your plaintext**. quicnprotochat's server is cryptographically excluded from reading message content.
|
||||
The fundamental difference: **classical protocols trust the server with your plaintext**. quicproquo's server is cryptographically excluded from reading message content.
|
||||
|
||||
---
|
||||
|
||||
## Protocol comparison matrix
|
||||
|
||||
| Property | IRC+SSL | XMPP+TLS | XMPP+OMEMO | Telegram (MTProto) | quicnprotochat |
|
||||
| Property | IRC+SSL | XMPP+TLS | XMPP+OMEMO | Telegram (MTProto) | quicproquo |
|
||||
|---|---|---|---|---|---|
|
||||
| **Transport encryption** | TLS (server-to-server optional) | STARTTLS / direct TLS | STARTTLS / direct TLS | MTProto 2.0 (custom) | QUIC + TLS 1.3 |
|
||||
| **End-to-end encryption** | None | None | Double Ratchet (1:1) | "Secret chats" only (1:1) | MLS RFC 9420 (groups native) |
|
||||
@@ -41,7 +41,7 @@ The fundamental difference: **classical protocols trust the server with your pla
|
||||
|
||||
---
|
||||
|
||||
## Deep dive: IRC+SSL vs. quicnprotochat
|
||||
## Deep dive: IRC+SSL vs. quicproquo
|
||||
|
||||
IRC (Internet Relay Chat) is the archetypal chat protocol, designed in 1988. Adding SSL/TLS wraps the TCP connection in transport encryption, but the protocol's security model remains fundamentally unchanged.
|
||||
|
||||
@@ -66,7 +66,7 @@ IRC (Internet Relay Chat) is the archetypal chat protocol, designed in 1988. Add
|
||||
4. **No post-compromise security.** There is no mechanism to recover from a key compromise. If a server is breached, all messages flowing through it are exposed indefinitely.
|
||||
5. **No identity binding.** NickServ password authentication is plaintext over the IRC protocol (inside TLS, but visible to the server). There is no cryptographic binding between a user's identity and their messages.
|
||||
|
||||
### What happens when Alice sends a message on quicnprotochat
|
||||
### What happens when Alice sends a message on quicproquo
|
||||
|
||||
```
|
||||
┌───────┐ ┌────────┐ ┌─────┐
|
||||
@@ -93,7 +93,7 @@ IRC (Internet Relay Chat) is the archetypal chat protocol, designed in 1988. Add
|
||||
|
||||
---
|
||||
|
||||
## Deep dive: XMPP+OMEMO vs. quicnprotochat
|
||||
## Deep dive: XMPP+OMEMO vs. quicproquo
|
||||
|
||||
XMPP with OMEMO (XEP-0384) adds end-to-end encryption via the Signal Double Ratchet protocol. This is a significant improvement over plain XMPP, but OMEMO inherits the limitations of the Signal Protocol for group messaging.
|
||||
|
||||
@@ -109,7 +109,7 @@ XMPP with OMEMO (XEP-0384) adds end-to-end encryption via the Signal Double Ratc
|
||||
3 encryptions per message
|
||||
O(n) cost per send
|
||||
|
||||
quicnprotochat MLS group (4 members)
|
||||
quicproquo MLS group (4 members)
|
||||
|
||||
Alice encrypts once with group epoch key:
|
||||
┌───────┐ ── MLS_encrypt(epoch_key) ──▶ Server
|
||||
@@ -120,7 +120,7 @@ XMPP with OMEMO (XEP-0384) adds end-to-end encryption via the Signal Double Ratc
|
||||
(all decrypt with same epoch key)
|
||||
```
|
||||
|
||||
| Property | XMPP+OMEMO groups | quicnprotochat MLS groups |
|
||||
| Property | XMPP+OMEMO groups | quicproquo MLS groups |
|
||||
|---|---|---|
|
||||
| **Encryption per message** | O(n) -- encrypt once per recipient | O(1) -- single MLS application message |
|
||||
| **Add member** | O(n) -- distribute sender keys to all | O(log n) -- single MLS Commit |
|
||||
@@ -131,7 +131,7 @@ XMPP with OMEMO (XEP-0384) adds end-to-end encryption via the Signal Double Ratc
|
||||
|
||||
---
|
||||
|
||||
## Deep dive: Telegram (MTProto) vs. quicnprotochat
|
||||
## Deep dive: Telegram (MTProto) vs. quicproquo
|
||||
|
||||
Telegram is often perceived as a "secure" messenger, but its default mode provides **no end-to-end encryption**. Only "Secret Chats" (1:1 only, not available on desktop) use E2E encryption.
|
||||
|
||||
@@ -163,7 +163,7 @@ Telegram is often perceived as a "secure" messenger, but its default mode provid
|
||||
|
||||
### Comparison
|
||||
|
||||
| Property | Telegram Cloud Chats | Telegram Secret Chats | quicnprotochat |
|
||||
| Property | Telegram Cloud Chats | Telegram Secret Chats | quicproquo |
|
||||
|---|---|---|---|
|
||||
| **Server reads plaintext** | Yes | No | No |
|
||||
| **Group E2E** | No | N/A (1:1 only) | Yes (MLS) |
|
||||
@@ -173,7 +173,7 @@ Telegram is often perceived as a "secure" messenger, but its default mode provid
|
||||
| **Open source server** | No | No | Yes (MIT license) |
|
||||
| **Post-quantum** | None | None | Hybrid KEM (X25519 + ML-KEM-768) |
|
||||
|
||||
**Critical concern with Telegram:** MTProto is a custom, proprietary cryptographic protocol that has not undergone the same level of independent cryptographic review as standard protocols (TLS, MLS, Signal Protocol). Multiple academic papers have identified weaknesses in earlier versions. quicnprotochat exclusively uses IETF-standardized protocols (TLS 1.3, MLS RFC 9420) and widely reviewed cryptographic primitives.
|
||||
**Critical concern with Telegram:** MTProto is a custom, proprietary cryptographic protocol that has not undergone the same level of independent cryptographic review as standard protocols (TLS, MLS, Signal Protocol). Multiple academic papers have identified weaknesses in earlier versions. quicproquo exclusively uses IETF-standardized protocols (TLS 1.3, MLS RFC 9420) and widely reviewed cryptographic primitives.
|
||||
|
||||
---
|
||||
|
||||
@@ -208,7 +208,7 @@ An attacker gains root access to the chat server.
|
||||
│ sees metadata (who talks to whom, │
|
||||
│ when, message sizes). │
|
||||
│ │
|
||||
│ quicnprotochat: │
|
||||
│ quicproquo: │
|
||||
│ Cannot read messages (MLS E2E). │
|
||||
│ Sees metadata (recipient keys, │
|
||||
│ timing, sizes). │
|
||||
@@ -243,7 +243,7 @@ A state-level adversary records all encrypted traffic today, planning to decrypt
|
||||
Telegram (MTProto / custom DH):
|
||||
└── Quantum computer breaks DH → all recorded messages decrypted
|
||||
|
||||
quicnprotochat (Hybrid KEM):
|
||||
quicproquo (Hybrid KEM):
|
||||
└── Transport: QUIC/TLS with ECDHE → quantum computer breaks this layer
|
||||
└── Inner layer: MLS content encrypted with group epoch keys
|
||||
└── Hybrid KEM envelope: X25519 + ML-KEM-768
|
||||
@@ -252,7 +252,7 @@ A state-level adversary records all encrypted traffic today, planning to decrypt
|
||||
└── Combined key: STILL SECURE (both must be broken)
|
||||
```
|
||||
|
||||
quicnprotochat's hybrid "belt and suspenders" design means that **even if X25519 falls to a quantum computer, ML-KEM-768 protects the content**. The adversary's recorded ciphertext remains useless.
|
||||
quicproquo's hybrid "belt and suspenders" design means that **even if X25519 falls to a quantum computer, ML-KEM-768 protects the content**. The adversary's recorded ciphertext remains useless.
|
||||
|
||||
### Scenario 3: Device theft / compromise
|
||||
|
||||
@@ -279,7 +279,7 @@ An attacker steals Alice's unlocked device and extracts her key material.
|
||||
Messages after T: all accessible (cloud sync)
|
||||
Recovery: terminate session from another device
|
||||
|
||||
quicnprotochat:
|
||||
quicproquo:
|
||||
Messages before T: protected (MLS forward secrecy, past epoch keys deleted)
|
||||
Messages after T: exposed only until next MLS epoch advance
|
||||
Recovery: ANY group member issues an MLS Update proposal →
|
||||
@@ -293,7 +293,7 @@ An attacker steals Alice's unlocked device and extracts her key material.
|
||||
|
||||
### Why QUIC over TCP
|
||||
|
||||
Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) blocking. quicnprotochat uses QUIC, which provides independent streams over UDP.
|
||||
Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) blocking. quicproquo uses QUIC, which provides independent streams over UDP.
|
||||
|
||||
```
|
||||
TCP (IRC/XMPP): all streams share one ordered byte stream
|
||||
@@ -308,7 +308,7 @@ Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) b
|
||||
└── ALL streams blocked until retransmit
|
||||
|
||||
|
||||
QUIC (quicnprotochat): each stream is independent
|
||||
QUIC (quicproquo): each stream is independent
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Stream A: ████████░░██████████████ (only A waits)
|
||||
@@ -334,7 +334,7 @@ Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) b
|
||||
════════════════════════════════════════════════════
|
||||
Total: 2-3 round trips before first message
|
||||
|
||||
quicnprotochat: QUIC integrates crypto into handshake = 1 RTT (or 0-RTT)
|
||||
quicproquo: QUIC integrates crypto into handshake = 1 RTT (or 0-RTT)
|
||||
──────────────────────────────────────────────────────────────────────────
|
||||
Client ──Initial(ClientHello)──▶ Server │
|
||||
Client ◀──Initial(ServerHello)── Server │ 1 RTT total
|
||||
@@ -363,7 +363,7 @@ Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) b
|
||||
Phone number + SMS OTP ← carrier and Telegram see phone number
|
||||
(identity = phone number) ← no cryptographic identity
|
||||
|
||||
quicnprotochat (OPAQUE PAKE):
|
||||
quicproquo (OPAQUE PAKE):
|
||||
Client ──blinded_element──▶ Server │ Server never sees password
|
||||
Client ◀──evaluated_element── Server │ Mutual authentication
|
||||
Client ──finalization──▶ Server │ Session key derived
|
||||
@@ -406,7 +406,7 @@ Classical protocols (IRC, XMPP) use TCP, which suffers from head-of-line (HOL) b
|
||||
│ Schema via XSD exists but rarely enforced at runtime. │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
|
||||
Cap'n Proto (quicnprotochat):
|
||||
Cap'n Proto (quicproquo):
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ [8-byte aligned struct with pointers] │
|
||||
│ │
|
||||
@@ -434,7 +434,7 @@ The following diagram maps each protocol against the security properties it prov
|
||||
Telegram Cloud · · · · · · · ·
|
||||
Telegram Secret △ · ● · · ● · ·
|
||||
Signal ● · ● ● △ ● · ·
|
||||
quicnprotochat ● ● ● ● ● ● ● ●
|
||||
quicproquo ● ● ● ● ● ● ● ●
|
||||
|
||||
Legend: ● = yes △ = partial · = no
|
||||
FS = forward secrecy PCS = post-compromise security
|
||||
@@ -446,12 +446,12 @@ The following diagram maps each protocol against the security properties it prov
|
||||
|
||||
---
|
||||
|
||||
## The quicnprotochat advantage: a layered defense
|
||||
## The quicproquo advantage: a layered defense
|
||||
|
||||
Classical protocols rely on a **single layer** of security (transport TLS). quicnprotochat applies defense in depth with **three independent layers**, each of which must be broken separately:
|
||||
Classical protocols rely on a **single layer** of security (transport TLS). quicproquo applies defense in depth with **three independent layers**, each of which must be broken separately:
|
||||
|
||||
```
|
||||
IRC+SSL security layers: quicnprotochat security layers:
|
||||
IRC+SSL security layers: quicproquo security layers:
|
||||
|
||||
┌─────────────────────────┐ ┌─────────────────────────────────┐
|
||||
│ TLS (transport) │ │ Layer 3: Hybrid KEM envelope │
|
||||
@@ -474,7 +474,7 @@ Classical protocols rely on a **single layer** of security (transport TLS). quic
|
||||
|
||||
To read a message, attacker must break:
|
||||
IRC+SSL: TLS (1 layer)
|
||||
quicnprotochat: TLS + MLS + Hybrid KEM (3 layers)
|
||||
quicproquo: TLS + MLS + Hybrid KEM (3 layers)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -483,7 +483,7 @@ Classical protocols rely on a **single layer** of security (transport TLS). quic
|
||||
|
||||
Fairness demands acknowledging where classical protocols genuinely excel:
|
||||
|
||||
| Advantage | IRC | quicnprotochat |
|
||||
| Advantage | IRC | quicproquo |
|
||||
|---|---|---|
|
||||
| **Simplicity** | Telnet-compatible text protocol | Binary protocol requiring client implementation |
|
||||
| **Maturity** | 35+ years of production use | Early-stage research project |
|
||||
@@ -493,7 +493,7 @@ Fairness demands acknowledging where classical protocols genuinely excel:
|
||||
| **Public channels** | Designed for open, unencrypted discussion | Designed for private, encrypted communication |
|
||||
| **Anonymity** | No identity required | Requires Ed25519 identity keypair |
|
||||
|
||||
IRC remains an excellent choice for **public, open discussion** where encryption is not needed and simplicity is valued. quicnprotochat is designed for a different threat model: private communication where **confidentiality, forward secrecy, and post-compromise security** are requirements, not luxuries.
|
||||
IRC remains an excellent choice for **public, open discussion** where encryption is not needed and simplicity is valued. quicproquo is designed for a different threat model: private communication where **confidentiality, forward secrecy, and post-compromise security** are requirements, not luxuries.
|
||||
|
||||
---
|
||||
|
||||
@@ -501,10 +501,10 @@ IRC remains an excellent choice for **public, open discussion** where encryption
|
||||
|
||||
For users and operators coming from classical chat systems, here is what changes practically:
|
||||
|
||||
| Concern | Classical (IRC/XMPP) | quicnprotochat |
|
||||
| Concern | Classical (IRC/XMPP) | quicproquo |
|
||||
|---|---|---|
|
||||
| **Server setup** | Install IRCd, configure TLS cert | `cargo build && ./quicnprotochat-server` (auto-generates TLS cert) |
|
||||
| **Client setup** | Install any IRC client | `./quicnprotochat-client register-user` (generates Ed25519 identity) |
|
||||
| **Server setup** | Install IRCd, configure TLS cert | `cargo build && ./qpq-server` (auto-generates TLS cert) |
|
||||
| **Client setup** | Install any IRC client | `./quicproquo-client register-user` (generates Ed25519 identity) |
|
||||
| **Joining a group** | `/join #channel` | Receive MLS Welcome message from group creator |
|
||||
| **Sending a message** | Type and press enter | Same -- client handles MLS encryption transparently |
|
||||
| **Server admin sees messages** | Yes (always) | No (never -- server sees only ciphertext) |
|
||||
@@ -518,7 +518,7 @@ For users and operators coming from classical chat systems, here is what changes
|
||||
|
||||
- [Why This Design, Not Signal/Matrix/...](why-not-signal.md) -- comparison with modern E2E-encrypted protocols
|
||||
- [Protocol Layers Overview](../protocol-layers/overview.md) -- detailed protocol stack documentation
|
||||
- [Threat Model](../cryptography/threat-model.md) -- what quicnprotochat does and does not protect against
|
||||
- [Threat Model](../cryptography/threat-model.md) -- what quicproquo does and does not protect against
|
||||
- [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md) -- hybrid KEM design and rationale
|
||||
- [MLS (RFC 9420)](../protocol-layers/mls.md) -- deep dive into the group key agreement protocol
|
||||
- [Architecture Overview](../architecture/overview.md) -- system-level architecture
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Why This Design, Not Signal/Matrix/...
|
||||
|
||||
This page compares quicnprotochat's protocol choices against two widely deployed secure messaging systems -- the Signal Protocol and the Matrix ecosystem (Olm/Megolm) -- to explain why a different architecture was chosen. The comparison covers four dimensions: group key agreement, transport, serialisation, and overall trade-offs.
|
||||
This page compares quicproquo's protocol choices against two widely deployed secure messaging systems -- the Signal Protocol and the Matrix ecosystem (Olm/Megolm) -- to explain why a different architecture was chosen. The comparison covers four dimensions: group key agreement, transport, serialisation, and overall trade-offs.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,11 +26,11 @@ The Signal Protocol was designed for **1:1 messaging** and later extended to gro
|
||||
- Group membership changes require O(n) pairwise Sender Key distributions. Adding or removing a member requires the affected member to generate a new Sender Key and distribute it to all n-1 other members.
|
||||
- The pairwise key exchange for initial setup is O(n^2): each of n members must establish a Double Ratchet session with each of the other n-1 members.
|
||||
|
||||
**Limitations for quicnprotochat's use case:**
|
||||
**Limitations for quicproquo's use case:**
|
||||
|
||||
- O(n^2) pairwise setup cost limits practical group size.
|
||||
- No post-compromise security for groups is a significant gap.
|
||||
- The protocol requires a central server for X3DH prekey bundle distribution (similar to quicnprotochat's AS, but tightly coupled to the Signal server).
|
||||
- The protocol requires a central server for X3DH prekey bundle distribution (similar to quicproquo's AS, but tightly coupled to the Signal server).
|
||||
|
||||
### Matrix / Olm / Megolm
|
||||
|
||||
@@ -54,15 +54,15 @@ The Matrix ecosystem uses two distinct cryptographic protocols:
|
||||
- **Eventually consistent state** model means that room membership, key sharing, and message ordering can diverge between homeservers. The client must reconcile these inconsistencies, adding complexity to the state machine.
|
||||
- **Device verification** is a persistent UX challenge. The cross-signing mechanism is powerful but difficult for users to understand.
|
||||
|
||||
**Limitations for quicnprotochat's use case:**
|
||||
**Limitations for quicproquo's use case:**
|
||||
|
||||
- No post-compromise security for groups (same limitation as Signal's Sender Keys).
|
||||
- Federation adds latency, metadata exposure, and state management complexity that quicnprotochat does not need.
|
||||
- Federation adds latency, metadata exposure, and state management complexity that quicproquo does not need.
|
||||
- JSON-based wire format is inefficient (see serialisation comparison below).
|
||||
|
||||
### quicnprotochat: MLS (RFC 9420)
|
||||
### quicproquo: MLS (RFC 9420)
|
||||
|
||||
quicnprotochat uses the **Messaging Layer Security (MLS)** protocol, standardized as RFC 9420 by the IETF.
|
||||
quicproquo uses the **Messaging Layer Security (MLS)** protocol, standardized as RFC 9420 by the IETF.
|
||||
|
||||
**Key properties:**
|
||||
|
||||
@@ -74,7 +74,7 @@ quicnprotochat uses the **Messaging Layer Security (MLS)** protocol, standardize
|
||||
|
||||
**Cost of group operations:**
|
||||
|
||||
| Operation | Signal (Sender Keys) | Matrix (Megolm) | MLS (quicnprotochat) |
|
||||
| Operation | Signal (Sender Keys) | Matrix (Megolm) | MLS (quicproquo) |
|
||||
|---|---|---|---|
|
||||
| Add member | O(n) Sender Key distributions | O(n) Megolm session shares | O(log n) tree update |
|
||||
| Remove member | O(n) Sender Key rotations | O(n) new Megolm session | O(log n) tree update |
|
||||
@@ -87,7 +87,7 @@ quicnprotochat uses the **Messaging Layer Security (MLS)** protocol, standardize
|
||||
|
||||
The transport layer determines how encrypted payloads reach the server and how client-server authentication is performed.
|
||||
|
||||
| Property | Signal | Matrix | quicnprotochat |
|
||||
| Property | Signal | Matrix | quicproquo |
|
||||
|---|---|---|---|
|
||||
| **Transport protocol** | TLS over TCP (HTTP/2) | HTTPS (TLS over TCP) | QUIC (UDP) + TLS 1.3 |
|
||||
| **Multiplexing** | HTTP/2 stream multiplexing | HTTP/1.1 or HTTP/2 | Native QUIC stream multiplexing |
|
||||
@@ -106,7 +106,7 @@ QUIC eliminates TCP head-of-line blocking, which is particularly important for a
|
||||
|
||||
The serialisation format determines the overhead of encoding and decoding messages, the type safety of the wire format, and the feasibility of schema evolution.
|
||||
|
||||
| Property | Signal (Protobuf) | Matrix (JSON) | quicnprotochat (Cap'n Proto) |
|
||||
| Property | Signal (Protobuf) | Matrix (JSON) | quicproquo (Cap'n Proto) |
|
||||
|---|---|---|---|
|
||||
| **Format** | Binary, schema-defined | Text, schema-optional (JSON Schema exists but is not enforced by the wire format) | Binary, schema-defined |
|
||||
| **Deserialization cost** | Requires a decode pass (allocates and copies) | Requires a parse pass (allocates, copies, and handles UTF-8) | **Zero-copy**: the wire bytes are the in-memory representation. Readers traverse pointers in-place. |
|
||||
@@ -118,7 +118,7 @@ The serialisation format determines the overhead of encoding and decoding messag
|
||||
|
||||
**Why Cap'n Proto over Protobuf?**
|
||||
|
||||
While Protobuf is a reasonable choice (and Signal uses it successfully), Cap'n Proto provides two features that are particularly valuable for quicnprotochat:
|
||||
While Protobuf is a reasonable choice (and Signal uses it successfully), Cap'n Proto provides two features that are particularly valuable for quicproquo:
|
||||
|
||||
1. **Zero-copy deserialization** eliminates a class of allocation and performance overhead. In a messaging system that processes many small messages, avoiding deserialization copies adds up.
|
||||
2. **Built-in RPC** means that Cap'n Proto is both the serialisation format and the RPC framework. There is no need for a separate gRPC or HTTP layer. The same `.capnp` schema file defines both the data structures and the service interface.
|
||||
@@ -128,7 +128,7 @@ While Protobuf is a reasonable choice (and Signal uses it successfully), Cap'n P
|
||||
|
||||
## Summary comparison table
|
||||
|
||||
| Dimension | Signal | Matrix | quicnprotochat |
|
||||
| Dimension | Signal | Matrix | quicproquo |
|
||||
|---|---|---|---|
|
||||
| **1:1 encryption** | Double Ratchet (FS + PCS) | Olm / Double Ratchet (FS + PCS) | MLS (FS + PCS) |
|
||||
| **Group encryption** | Sender Keys (FS only) | Megolm (FS only) | MLS (FS + PCS) |
|
||||
@@ -143,13 +143,13 @@ While Protobuf is a reasonable choice (and Signal uses it successfully), Cap'n P
|
||||
|
||||
---
|
||||
|
||||
## What quicnprotochat gives up
|
||||
## What quicproquo gives up
|
||||
|
||||
No design is without trade-offs. Compared to Signal and Matrix, quicnprotochat:
|
||||
No design is without trade-offs. Compared to Signal and Matrix, quicproquo:
|
||||
|
||||
- **Has no federation.** A single server per deployment means no decentralized architecture. This is a deliberate simplification -- federation adds significant complexity and metadata exposure.
|
||||
- **Is less mature.** Signal and Matrix have years of production hardening, formal security audits, and battle-tested implementations. quicnprotochat is in early development.
|
||||
- **Has a smaller ecosystem.** Signal and Matrix have extensive client libraries, bridges, and integrations. quicnprotochat is a standalone Rust implementation.
|
||||
- **Is less mature.** Signal and Matrix have years of production hardening, formal security audits, and battle-tested implementations. quicproquo is in early development.
|
||||
- **Has a smaller ecosystem.** Signal and Matrix have extensive client libraries, bridges, and integrations. quicproquo is a standalone Rust implementation.
|
||||
- **Requires MLS client complexity.** MLS clients must maintain a ratchet tree, process Commits, and handle epoch transitions. This is more complex than a simple symmetric ratchet (Sender Keys / Megolm), though the complexity buys post-compromise security.
|
||||
|
||||
---
|
||||
@@ -158,6 +158,6 @@ No design is without trade-offs. Compared to Signal and Matrix, quicnprotochat:
|
||||
|
||||
- [Design Decisions Overview](overview.md) -- index of all ADRs
|
||||
- [ADR-002: Cap'n Proto over MessagePack](adr-002-capnproto.md) -- serialisation format choice
|
||||
- [Protocol Layers Overview](../protocol-layers/overview.md) -- how quicnprotochat's layers compose
|
||||
- [Protocol Layers Overview](../protocol-layers/overview.md) -- how quicproquo's layers compose
|
||||
- [MLS (RFC 9420)](../protocol-layers/mls.md) -- deep dive into the MLS protocol layer
|
||||
- [Architecture Overview](../architecture/overview.md) -- system-level architecture
|
||||
|
||||
@@ -16,10 +16,10 @@ This compiles all four crates:
|
||||
|
||||
| Crate | Type | Purpose |
|
||||
|---|---|---|
|
||||
| `quicnprotochat-core` | library | Crypto primitives, MLS `GroupMember` state machine, hybrid KEM |
|
||||
| `quicnprotochat-proto` | library | Cap'n Proto schemas, generated types, envelope serialisation helpers |
|
||||
| `quicnprotochat-server` | binary | Unified Authentication + Delivery Service (`NodeService`) |
|
||||
| `quicnprotochat-client` | binary | CLI client with subcommands (`ping`, `register`, `send`, `recv`, etc.) |
|
||||
| `quicproquo-core` | library | Crypto primitives, MLS `GroupMember` state machine, hybrid KEM |
|
||||
| `quicproquo-proto` | library | Cap'n Proto schemas, generated types, envelope serialisation helpers |
|
||||
| `quicproquo-server` | binary | Unified Authentication + Delivery Service (`NodeService`) |
|
||||
| `quicproquo-client` | binary | CLI client with subcommands (`ping`, `register`, `send`, `recv`, etc.) |
|
||||
|
||||
For a release build with LTO, symbol stripping, and single codegen unit:
|
||||
|
||||
@@ -47,25 +47,25 @@ cargo test --workspace
|
||||
|
||||
The test suite includes:
|
||||
|
||||
- **`quicnprotochat-proto`**: Round-trip serialisation tests for Cap'n Proto `Envelope` messages (Ping, Pong, corrupted-input error handling).
|
||||
- **`quicnprotochat-core`**: Two-party MLS round-trip (`create_group` / `add_member` / `send_message` / `receive_message`), group ID lifecycle assertions.
|
||||
- **`quicnprotochat-client`**: Integration tests for MLS group operations and auth service interactions (require a running server or use in-process mocks).
|
||||
- **`quicproquo-proto`**: Round-trip serialisation tests for Cap'n Proto `Envelope` messages (Ping, Pong, corrupted-input error handling).
|
||||
- **`quicproquo-core`**: Two-party MLS round-trip (`create_group` / `add_member` / `send_message` / `receive_message`), group ID lifecycle assertions.
|
||||
- **`quicproquo-client`**: Integration tests for MLS group operations and auth service interactions (require a running server or use in-process mocks).
|
||||
|
||||
To run tests for a single crate:
|
||||
|
||||
```bash
|
||||
cargo test -p quicnprotochat-core
|
||||
cargo test -p quicproquo-core
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cap'n Proto code generation
|
||||
|
||||
The `quicnprotochat-proto` crate does not contain hand-written Rust types for wire messages. Instead, its `build.rs` script invokes the `capnp` compiler at build time to generate Rust source from the `.capnp` schema files.
|
||||
The `quicproquo-proto` crate does not contain hand-written Rust types for wire messages. Instead, its `build.rs` script invokes the `capnp` compiler at build time to generate Rust source from the `.capnp` schema files.
|
||||
|
||||
### How it works
|
||||
|
||||
1. `build.rs` locates the workspace-root `schemas/` directory (two levels above `crates/quicnprotochat-proto/`).
|
||||
1. `build.rs` locates the workspace-root `schemas/` directory (two levels above `crates/quicproquo-proto/`).
|
||||
2. It invokes `capnpc::CompilerCommand` on all four schema files:
|
||||
- `schemas/envelope.capnp` -- top-level wire envelope with `MsgType` discriminant
|
||||
- `schemas/auth.capnp` -- `AuthenticationService` RPC interface
|
||||
@@ -82,7 +82,7 @@ The `build.rs` script emits `cargo:rerun-if-changed` directives for each schema
|
||||
|
||||
The `src_prefix` is set to the `schemas/` directory so that inter-schema imports (e.g., `using Auth = import "auth.capnp".Auth;` inside `node.capnp`) resolve correctly.
|
||||
|
||||
### Design constraints of quicnprotochat-proto
|
||||
### Design constraints of quicproquo-proto
|
||||
|
||||
The proto crate is intentionally restricted:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Certificate lifecycle and CA-signed TLS
|
||||
|
||||
This page describes how to use CA-issued certificates with quicnprotochat and how to think about certificate pinning, rotation, and lifecycle.
|
||||
This page describes how to use CA-issued certificates with quicproquo and how to think about certificate pinning, rotation, and lifecycle.
|
||||
|
||||
For basic server TLS setup (self-signed certs, generation), see [Running the Server](running-the-server.md#tls-certificate-handling).
|
||||
|
||||
@@ -8,8 +8,8 @@ For basic server TLS setup (self-signed certs, generation), see [Running the Ser
|
||||
|
||||
## Current behaviour
|
||||
|
||||
- **Server:** Uses a single TLS certificate and private key (DER format). If the files are missing and the server is not in production mode, it generates a self-signed certificate. Production mode (`QUICNPROTOCHAT_PRODUCTION=1`) requires existing cert and key files.
|
||||
- **Client:** Trusts exactly the roots in the file given by `--ca-cert` (or `QUICNPROTOCHAT_CA_CERT`). Typically this is the server's own certificate (pinning) or a CA that signed the server cert.
|
||||
- **Server:** Uses a single TLS certificate and private key (DER format). If the files are missing and the server is not in production mode, it generates a self-signed certificate. Production mode (`QPQ_PRODUCTION=1`) requires existing cert and key files.
|
||||
- **Client:** Trusts exactly the roots in the file given by `--ca-cert` (or `QPQ_CA_CERT`). Typically this is the server's own certificate (pinning) or a CA that signed the server cert.
|
||||
|
||||
---
|
||||
|
||||
@@ -20,7 +20,7 @@ To pin the server so the client only connects to that server:
|
||||
1. Copy the server's certificate file (e.g. `data/server-cert.der`) from the server (or your deployment).
|
||||
2. Use that file as the client's CA cert:
|
||||
```bash
|
||||
quicnprotochat --ca-cert /path/to/server-cert.der ...
|
||||
qpq --ca-cert /path/to/server-cert.der ...
|
||||
```
|
||||
3. The client will only accept a connection if the server presents that exact certificate (or a chain ending in it). No separate CA bundle is required.
|
||||
|
||||
@@ -43,12 +43,12 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
|
||||
```
|
||||
2. **Configure the server** to use those paths:
|
||||
```bash
|
||||
export QUICNPROTOCHAT_TLS_CERT=/etc/quicnprotochat/server-cert.der
|
||||
export QUICNPROTOCHAT_TLS_KEY=/etc/quicnprotochat/server-key.der
|
||||
export QPQ_TLS_CERT=/etc/quicproquo/server-cert.der
|
||||
export QPQ_TLS_KEY=/etc/quicproquo/server-key.der
|
||||
```
|
||||
3. **Configure the client** to trust the CA that signed the server cert. Use the CA’s certificate (or the CA bundle) as `--ca-cert`:
|
||||
```bash
|
||||
quicnprotochat --ca-cert /etc/ssl/certs/your-ca.der --server-name your.server.example ...
|
||||
qpq --ca-cert /etc/ssl/certs/your-ca.der --server-name your.server.example ...
|
||||
```
|
||||
The `--server-name` must match the certificate’s SAN (e.g. DNS name).
|
||||
|
||||
@@ -60,7 +60,7 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
|
||||
|
||||
- **Manual rotation:** Replace `server-cert.der` and `server-key.der` on disk, then restart the server. Clients that pin the new cert must be updated with the new cert file.
|
||||
- **Let’s Encrypt renewal:** After renewing (e.g. via certbot), convert the new cert and key to DER, replace the files, and restart the server. If clients use the CA cert (e.g. ISRG Root X1) as `--ca-cert`, they do not need updates when the server cert is renewed.
|
||||
- **OCSP / CRL:** The quicnprotochat server does not currently perform OCSP stapling or CRL checks. Revocation is handled by the client or by operational procedures (e.g. short-lived certs, rotation on compromise).
|
||||
- **OCSP / CRL:** The quicproquo server does not currently perform OCSP stapling or CRL checks. Revocation is handled by the client or by operational procedures (e.g. short-lived certs, rotation on compromise).
|
||||
|
||||
---
|
||||
|
||||
@@ -70,6 +70,6 @@ To use a certificate issued by a public CA (e.g. Let's Encrypt):
|
||||
|------------------|-------------|--------------------|
|
||||
| Pinned (single server) | Self-signed or any | Server’s cert file |
|
||||
| CA-issued | Let’s Encrypt (or other CA) | CA cert (or bundle) |
|
||||
| Production | Always use existing cert/key; set `QUICNPROTOCHAT_PRODUCTION=1` | CA or pinned server cert |
|
||||
| Production | Always use existing cert/key; set `QPQ_PRODUCTION=1` | CA or pinned server cert |
|
||||
|
||||
For production, prefer either (a) certificate pinning with the server’s cert or (b) a CA-issued server cert with clients trusting the CA, and plan for rotation and restart (or future reload support).
|
||||
|
||||
@@ -75,13 +75,13 @@ You will need **three terminal windows**: one for the server, one for Alice, and
|
||||
In **Terminal 1** (Server):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-server
|
||||
cargo run -p quicproquo-server
|
||||
```
|
||||
|
||||
Wait for the log line confirming it is accepting connections:
|
||||
|
||||
```
|
||||
INFO quicnprotochat_server: accepting QUIC connections addr="0.0.0.0:7000"
|
||||
INFO quicproquo_server: accepting QUIC connections addr="0.0.0.0:7000"
|
||||
```
|
||||
|
||||
If this is the first run, you will also see a log line about generating the self-signed TLS certificate. The certificate is written to `data/server-cert.der`, which the client will use for TLS verification.
|
||||
@@ -91,7 +91,7 @@ If this is the first run, you will also see a log line about generating the self
|
||||
In **Terminal 2** (Alice):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- register-state \
|
||||
cargo run -p quicproquo-client -- register-state \
|
||||
--state alice.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -116,7 +116,7 @@ KeyPackage uploaded successfully.
|
||||
In **Terminal 3** (Bob):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- register-state \
|
||||
cargo run -p quicproquo-client -- register-state \
|
||||
--state bob.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -137,7 +137,7 @@ In **Terminal 2** (Alice):
|
||||
First, create the group:
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- create-group \
|
||||
cargo run -p quicproquo-client -- create-group \
|
||||
--state alice.bin \
|
||||
--group-id "demo-chat"
|
||||
```
|
||||
@@ -151,7 +151,7 @@ Alice is now the sole member of the group at epoch 0.
|
||||
Next, invite Bob using his identity key from Step 3:
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- invite \
|
||||
cargo run -p quicproquo-client -- invite \
|
||||
--state alice.bin \
|
||||
--peer-key <BOB_KEY> \
|
||||
--server 127.0.0.1:7000
|
||||
@@ -173,7 +173,7 @@ Alice's group state has now advanced to epoch 1.
|
||||
In **Terminal 3** (Bob):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- join \
|
||||
cargo run -p quicproquo-client -- join \
|
||||
--state bob.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -195,7 +195,7 @@ Bob is now a member of the group at epoch 1, sharing the same group secret as Al
|
||||
In **Terminal 2** (Alice):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- send \
|
||||
cargo run -p quicproquo-client -- send \
|
||||
--state alice.bin \
|
||||
--peer-key <BOB_KEY> \
|
||||
--msg "Hello Bob, this is encrypted with MLS!" \
|
||||
@@ -215,7 +215,7 @@ message sent
|
||||
In **Terminal 3** (Bob):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- recv \
|
||||
cargo run -p quicproquo-client -- recv \
|
||||
--state bob.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -233,7 +233,7 @@ This command:
|
||||
In **Terminal 3** (Bob):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- send \
|
||||
cargo run -p quicproquo-client -- send \
|
||||
--state bob.bin \
|
||||
--peer-key <ALICE_KEY> \
|
||||
--msg "Hi Alice, received loud and clear!" \
|
||||
@@ -249,7 +249,7 @@ message sent
|
||||
In **Terminal 2** (Alice):
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- recv \
|
||||
cargo run -p quicproquo-client -- recv \
|
||||
--state alice.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -266,7 +266,7 @@ If you want to see the entire flow in a single command without managing three te
|
||||
|
||||
```bash
|
||||
# Ensure the server is running, then:
|
||||
cargo run -p quicnprotochat-client -- demo-group --server 127.0.0.1:7000
|
||||
cargo run -p quicproquo-client -- demo-group --server 127.0.0.1:7000
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Docker Deployment
|
||||
|
||||
quicnprotochat includes a multi-stage Dockerfile and a Docker Compose configuration for building and running the server in containers.
|
||||
quicproquo includes a multi-stage Dockerfile and a Docker Compose configuration for building and running the server in containers.
|
||||
|
||||
---
|
||||
|
||||
@@ -40,7 +40,7 @@ services:
|
||||
- "7000:7000"
|
||||
environment:
|
||||
RUST_LOG: "info"
|
||||
QUICNPROTOCHAT_LISTEN: "0.0.0.0:7000"
|
||||
QPQ_LISTEN: "0.0.0.0:7000"
|
||||
healthcheck:
|
||||
test: ["CMD", "bash", "-c", "echo '' > /dev/tcp/localhost/7000"]
|
||||
interval: 5s
|
||||
@@ -81,9 +81,9 @@ RUN apt-get update \
|
||||
Key steps:
|
||||
|
||||
1. **Base image**: `rust:bookworm` (Debian Bookworm with the Rust toolchain pre-installed).
|
||||
2. **Install `capnproto`**: Required by `quicnprotochat-proto/build.rs` to compile `.capnp` schemas at build time.
|
||||
2. **Install `capnproto`**: Required by `quicproquo-proto/build.rs` to compile `.capnp` schemas at build time.
|
||||
3. **Copy manifests first**: `Cargo.toml` and `Cargo.lock` are copied before source code. Dummy `main.rs` / `lib.rs` stubs are created so that `cargo build` can resolve and cache the dependency graph. This ensures that dependency compilation is cached in a separate Docker layer -- subsequent builds that only change source code skip the dependency compilation step entirely.
|
||||
4. **Copy schemas**: The `schemas/` directory is copied before the dependency build because `quicnprotochat-proto/build.rs` requires the `.capnp` files during compilation.
|
||||
4. **Copy schemas**: The `schemas/` directory is copied before the dependency build because `quicproquo-proto/build.rs` requires the `.capnp` files during compilation.
|
||||
5. **Copy real source and build**: After the dependency cache layer, real source files are copied in and `cargo build --release` is run.
|
||||
|
||||
### Stage 2: Runtime (`debian:bookworm-slim`)
|
||||
@@ -95,16 +95,16 @@ RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /build/target/release/quicnprotochat-server /usr/local/bin/quicnprotochat-server
|
||||
COPY --from=builder /build/target/release/qpq-server /usr/local/bin/qpq-server
|
||||
|
||||
EXPOSE 7000
|
||||
|
||||
ENV RUST_LOG=info \
|
||||
QUICNPROTOCHAT_LISTEN=0.0.0.0:7000
|
||||
QPQ_LISTEN=0.0.0.0:7000
|
||||
|
||||
USER nobody
|
||||
|
||||
CMD ["quicnprotochat-server"]
|
||||
CMD ["qpq-server"]
|
||||
```
|
||||
|
||||
Key characteristics:
|
||||
@@ -112,9 +112,9 @@ Key characteristics:
|
||||
- **Minimal image**: No Rust toolchain, no `capnp` compiler, no build artifacts.
|
||||
- **`ca-certificates`**: Included for future HTTPS calls (e.g., ACME certificate provisioning or key sync endpoints).
|
||||
- **Non-root execution**: The container runs as `nobody` for defense in depth.
|
||||
- **Default port**: The Dockerfile defaults to port `7000` via `QUICNPROTOCHAT_LISTEN`, but the `docker-compose.yml` overrides this to `7000` for consistency with the development workflow.
|
||||
- **Default port**: The Dockerfile defaults to port `7000` via `QPQ_LISTEN`, but the `docker-compose.yml` overrides this to `7000` for consistency with the development workflow.
|
||||
|
||||
> **Note**: The `EXPOSE 7000` directive in the Dockerfile and the `QUICNPROTOCHAT_LISTEN=0.0.0.0:7000` override in `docker-compose.yml` mean the effective listen port is `7000` when using Compose. If you run the Docker image directly without Compose, the server will listen on `7000` by default.
|
||||
> **Note**: The `EXPOSE 7000` directive in the Dockerfile and the `QPQ_LISTEN=0.0.0.0:7000` override in `docker-compose.yml` mean the effective listen port is `7000` when using Compose. If you run the Docker image directly without Compose, the server will listen on `7000` by default.
|
||||
|
||||
---
|
||||
|
||||
@@ -129,7 +129,7 @@ services:
|
||||
volumes:
|
||||
- server-data:/data
|
||||
environment:
|
||||
QUICNPROTOCHAT_DATA_DIR: "/data"
|
||||
QPQ_DATA_DIR: "/data"
|
||||
|
||||
volumes:
|
||||
server-data:
|
||||
@@ -140,7 +140,7 @@ Or use a bind mount for easier inspection:
|
||||
```bash
|
||||
docker compose run \
|
||||
-v $(pwd)/server-data:/data \
|
||||
-e QUICNPROTOCHAT_DATA_DIR=/data \
|
||||
-e QPQ_DATA_DIR=/data \
|
||||
server
|
||||
```
|
||||
|
||||
@@ -153,18 +153,18 @@ Without a volume, all server state (including TLS certificates and message queue
|
||||
To build the Docker image without starting a container:
|
||||
|
||||
```bash
|
||||
docker build -t quicnprotochat-server -f docker/Dockerfile .
|
||||
docker build -t qpq-server -f docker/Dockerfile .
|
||||
```
|
||||
|
||||
To run it manually:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name quicnprotochat \
|
||||
--name quicproquo \
|
||||
-p 7000:7000/udp \
|
||||
-e QUICNPROTOCHAT_LISTEN=0.0.0.0:7000 \
|
||||
-e QPQ_LISTEN=0.0.0.0:7000 \
|
||||
-e RUST_LOG=info \
|
||||
quicnprotochat-server
|
||||
qpq-server
|
||||
```
|
||||
|
||||
Note the `/udp` suffix on the port mapping -- QUIC runs over UDP.
|
||||
@@ -180,7 +180,7 @@ When the server runs in Docker with `docker compose up`, the client can connect
|
||||
docker compose cp server:/data/server-cert.der ./data/server-cert.der
|
||||
|
||||
# Connect
|
||||
cargo run -p quicnprotochat-client -- ping \
|
||||
cargo run -p quicproquo-client -- ping \
|
||||
--ca-cert ./data/server-cert.der \
|
||||
--server-name localhost
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Prerequisites
|
||||
|
||||
Before building quicnprotochat you need a Rust toolchain and the Cap'n Proto schema compiler. Docker is optional but useful for reproducible builds and deployment.
|
||||
Before building quicproquo you need a Rust toolchain and the Cap'n Proto schema compiler. Docker is optional but useful for reproducible builds and deployment.
|
||||
|
||||
---
|
||||
|
||||
@@ -8,7 +8,7 @@ Before building quicnprotochat you need a Rust toolchain and the Cap'n Proto sch
|
||||
|
||||
**Minimum supported Rust version: 1.77+ (stable)**
|
||||
|
||||
quicnprotochat uses the 2021 edition and workspace resolver v2. Any stable Rust release from 1.77 onward should work. Install or update via [rustup](https://rustup.rs/):
|
||||
quicproquo uses the 2021 edition and workspace resolver v2. Any stable Rust release from 1.77 onward should work. Install or update via [rustup](https://rustup.rs/):
|
||||
|
||||
```bash
|
||||
# Install rustup (if not already present)
|
||||
@@ -29,7 +29,7 @@ The workspace depends on several crates that use procedural macros (`serde_deriv
|
||||
|
||||
## Cap'n Proto compiler (`capnp`)
|
||||
|
||||
The `quicnprotochat-proto` crate runs a `build.rs` script that invokes the `capnp` binary at compile time to generate Rust types from the `.capnp` schema files in `schemas/`. The `capnp` binary must be on your `PATH`.
|
||||
The `quicproquo-proto` crate runs a `build.rs` script that invokes the `capnp` binary at compile time to generate Rust types from the `.capnp` schema files in `schemas/`. The `capnp` binary must be on your `PATH`.
|
||||
|
||||
### Debian / Ubuntu
|
||||
|
||||
@@ -74,7 +74,7 @@ See [Building from Source -- Troubleshooting](building.md#troubleshooting) for m
|
||||
|
||||
## Optional: Docker and Docker Compose
|
||||
|
||||
If you prefer to build and run quicnprotochat in containers, you will need:
|
||||
If you prefer to build and run quicproquo in containers, you will need:
|
||||
|
||||
- **Docker Engine** 20.10+ (or Docker Desktop)
|
||||
- **Docker Compose** v2+ (the `docker compose` plugin, not the legacy `docker-compose` binary)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Running the Client
|
||||
|
||||
The quicnprotochat CLI client provides subcommands for connectivity testing, identity registration, KeyPackage exchange, and persistent group messaging. All commands connect to the server over QUIC + TLS 1.3 and issue Cap'n Proto RPC calls against the `NodeService` endpoint.
|
||||
The quicproquo CLI client provides subcommands for connectivity testing, identity registration, KeyPackage exchange, and persistent group messaging. All commands connect to the server over QUIC + TLS 1.3 and issue Cap'n Proto RPC calls against the `NodeService` endpoint.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,8 +10,8 @@ These flags apply to every subcommand:
|
||||
|
||||
| Flag | Env var | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `--ca-cert` | `QUICNPROTOCHAT_CA_CERT` | `data/server-cert.der` | Path to the server's TLS certificate (DER format). The client uses this to verify the server's identity during the TLS handshake. |
|
||||
| `--server-name` | `QUICNPROTOCHAT_SERVER_NAME` | `localhost` | Expected TLS server name. Must match a SAN in the server's certificate. |
|
||||
| `--ca-cert` | `QPQ_CA_CERT` | `data/server-cert.der` | Path to the server's TLS certificate (DER format). The client uses this to verify the server's identity during the TLS handshake. |
|
||||
| `--server-name` | `QPQ_SERVER_NAME` | `localhost` | Expected TLS server name. Must match a SAN in the server's certificate. |
|
||||
|
||||
Most subcommands also accept `--server` (default `127.0.0.1:7000`) to specify the server address.
|
||||
|
||||
@@ -24,11 +24,11 @@ Most subcommands also accept `--server` (default `127.0.0.1:7000`) to specify th
|
||||
Send a health probe to the server and print the round-trip time.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- ping
|
||||
cargo run -p quicproquo-client -- ping
|
||||
```
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- ping --server 192.168.1.10:7000
|
||||
cargo run -p quicproquo-client -- ping --server 192.168.1.10:7000
|
||||
```
|
||||
|
||||
**Output:**
|
||||
@@ -49,7 +49,7 @@ These commands generate a fresh identity keypair in memory each time they run. T
|
||||
Generate a fresh Ed25519 identity, create an MLS KeyPackage, and upload it to the Authentication Service.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- register
|
||||
cargo run -p quicproquo-client -- register
|
||||
```
|
||||
|
||||
**Output:**
|
||||
@@ -66,7 +66,7 @@ Share the `identity_key` value with peers who want to add you to a group. They w
|
||||
Fetch a peer's KeyPackage from the Authentication Service by their Ed25519 public key.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- fetch-key a1b2c3d4e5f6...
|
||||
cargo run -p quicproquo-client -- fetch-key a1b2c3d4e5f6...
|
||||
```
|
||||
|
||||
The `identity_key` argument must be exactly 64 lowercase hex characters (32 bytes).
|
||||
@@ -90,7 +90,7 @@ KeyPackages are single-use: fetching a KeyPackage atomically removes it from the
|
||||
Run a complete Alice-and-Bob MLS round-trip against a live server. Both identities are created in-process; both communicate through the server's AS and DS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- demo-group --server 127.0.0.1:7000
|
||||
cargo run -p quicproquo-client -- demo-group --server 127.0.0.1:7000
|
||||
```
|
||||
|
||||
**Output:**
|
||||
@@ -106,21 +106,21 @@ This is the fastest way to verify that the entire stack (QUIC + TLS + Cap'n Prot
|
||||
|
||||
## Persistent group commands
|
||||
|
||||
These commands use a state file (`--state`, default `quicnprotochat-state.bin`) to persist the Ed25519 identity seed and MLS group state between invocations. A companion key store file (same path with `.ks` extension) holds HPKE init private keys.
|
||||
These commands use a state file (`--state`, default `qpq-state.bin`) to persist the Ed25519 identity seed and MLS group state between invocations. A companion key store file (same path with `.ks` extension) holds HPKE init private keys.
|
||||
|
||||
All persistent commands share the `--state` flag:
|
||||
|
||||
| Flag | Env var | Default |
|
||||
|---|---|---|
|
||||
| `--state` | `QUICNPROTOCHAT_STATE` | `quicnprotochat-state.bin` |
|
||||
| `--server` | `QUICNPROTOCHAT_SERVER` | `127.0.0.1:7000` |
|
||||
| `--state` | `QPQ_STATE` | `qpq-state.bin` |
|
||||
| `--server` | `QPQ_SERVER` | `127.0.0.1:7000` |
|
||||
|
||||
### `register-state`
|
||||
|
||||
Create or load a persistent identity, generate a KeyPackage, and upload it to the AS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- register-state \
|
||||
cargo run -p quicproquo-client -- register-state \
|
||||
--state alice.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -141,10 +141,10 @@ Refresh the KeyPackage on the server using your **existing** state file. Does no
|
||||
- Your KeyPackage has expired (server TTL, e.g. 24h).
|
||||
- Your KeyPackage was consumed (someone invited you) and you want to be invitable again.
|
||||
|
||||
Run with the same `--access-token` (or `QUICNPROTOCHAT_ACCESS_TOKEN`) as for other commands.
|
||||
Run with the same `--access-token` (or `QPQ_ACCESS_TOKEN`) as for other commands.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- refresh-keypackage \
|
||||
cargo run -p quicproquo-client -- refresh-keypackage \
|
||||
--state alice.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -163,7 +163,7 @@ If you are told "no key" when someone tries to invite you, have them wait and ru
|
||||
Create a new MLS group. The caller becomes the sole member at epoch 0.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- create-group \
|
||||
cargo run -p quicproquo-client -- create-group \
|
||||
--state alice.bin \
|
||||
--group-id "project-chat"
|
||||
```
|
||||
@@ -180,7 +180,7 @@ The group state is saved to the state file. You can now invite peers with `invit
|
||||
Fetch a peer's KeyPackage from the AS, add them to the group, and deliver the Welcome message via the DS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- invite \
|
||||
cargo run -p quicproquo-client -- invite \
|
||||
--state alice.bin \
|
||||
--peer-key b9a8c7d6e5f4... \
|
||||
--server 127.0.0.1:7000
|
||||
@@ -202,7 +202,7 @@ invited peer (welcome queued)
|
||||
Join a group by consuming a Welcome message from the DS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- join \
|
||||
cargo run -p quicproquo-client -- join \
|
||||
--state bob.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -219,7 +219,7 @@ joined group successfully
|
||||
Encrypt and send an application message to a peer via the DS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- send \
|
||||
cargo run -p quicproquo-client -- send \
|
||||
--state alice.bin \
|
||||
--peer-key b9a8c7d6e5f4... \
|
||||
--msg "hello from alice" \
|
||||
@@ -238,7 +238,7 @@ message sent
|
||||
Receive and decrypt all pending messages from the DS.
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-client -- recv \
|
||||
cargo run -p quicproquo-client -- recv \
|
||||
--state bob.bin \
|
||||
--server 127.0.0.1:7000
|
||||
```
|
||||
@@ -257,12 +257,12 @@ Additional flags:
|
||||
|
||||
```bash
|
||||
# Wait up to 5 seconds for messages
|
||||
cargo run -p quicnprotochat-client -- recv \
|
||||
cargo run -p quicproquo-client -- recv \
|
||||
--state bob.bin \
|
||||
--wait-ms 5000
|
||||
|
||||
# Stream messages continuously
|
||||
cargo run -p quicnprotochat-client -- recv \
|
||||
cargo run -p quicproquo-client -- recv \
|
||||
--state bob.bin \
|
||||
--stream --wait-ms 10000
|
||||
```
|
||||
@@ -271,7 +271,7 @@ cargo run -p quicnprotochat-client -- recv \
|
||||
|
||||
## HPKE init key lifecycle warning
|
||||
|
||||
The MLS protocol requires that the HPKE init private key generated during KeyPackage creation is available when processing the corresponding Welcome message. In quicnprotochat, this private key is stored in the key store file (`.ks` extension alongside the state file).
|
||||
The MLS protocol requires that the HPKE init private key generated during KeyPackage creation is available when processing the corresponding Welcome message. In quicproquo, this private key is stored in the key store file (`.ks` extension alongside the state file).
|
||||
|
||||
**The same state file and key store must be used for both `register-state` and `join`.** If you:
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Running the Server
|
||||
|
||||
The quicnprotochat server is a single binary (`quicnprotochat-server`) that exposes a unified **NodeService** endpoint combining Authentication Service (KeyPackage management) and Delivery Service (message relay) operations over a single QUIC + TLS 1.3 connection.
|
||||
The quicproquo server is a single binary (`qpq-server`) that exposes a unified **NodeService** endpoint combining Authentication Service (KeyPackage management) and Delivery Service (message relay) operations over a single QUIC + TLS 1.3 connection.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-server
|
||||
cargo run -p quicproquo-server
|
||||
```
|
||||
|
||||
On first launch the server will:
|
||||
@@ -20,8 +20,8 @@ On first launch the server will:
|
||||
You should see output similar to:
|
||||
|
||||
```
|
||||
2025-01-01T00:00:00.000000Z INFO quicnprotochat_server: generated self-signed TLS certificate cert="data/server-cert.der" key="data/server-key.der"
|
||||
2025-01-01T00:00:00.000000Z INFO quicnprotochat_server: accepting QUIC connections addr="0.0.0.0:7000"
|
||||
2025-01-01T00:00:00.000000Z INFO quicproquo_server: generated self-signed TLS certificate cert="data/server-cert.der" key="data/server-key.der"
|
||||
2025-01-01T00:00:00.000000Z INFO quicproquo_server: accepting QUIC connections addr="0.0.0.0:7000"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -32,36 +32,36 @@ All configuration is available via CLI flags and environment variables. Environm
|
||||
|
||||
| Purpose | CLI flag | Env var | Default |
|
||||
|---|---|---|---|
|
||||
| QUIC listen address | `--listen` | `QUICNPROTOCHAT_LISTEN` | `0.0.0.0:7000` |
|
||||
| TLS certificate (DER) | `--tls-cert` | `QUICNPROTOCHAT_TLS_CERT` | `data/server-cert.der` |
|
||||
| TLS private key (DER) | `--tls-key` | `QUICNPROTOCHAT_TLS_KEY` | `data/server-key.der` |
|
||||
| Data directory | `--data-dir` | `QUICNPROTOCHAT_DATA_DIR` | `data` |
|
||||
| QUIC listen address | `--listen` | `QPQ_LISTEN` | `0.0.0.0:7000` |
|
||||
| TLS certificate (DER) | `--tls-cert` | `QPQ_TLS_CERT` | `data/server-cert.der` |
|
||||
| TLS private key (DER) | `--tls-key` | `QPQ_TLS_KEY` | `data/server-key.der` |
|
||||
| Data directory | `--data-dir` | `QPQ_DATA_DIR` | `data` |
|
||||
| Log level | -- | `RUST_LOG` | `info` |
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Listen on a custom port
|
||||
cargo run -p quicnprotochat-server -- --listen 0.0.0.0:9000
|
||||
cargo run -p quicproquo-server -- --listen 0.0.0.0:9000
|
||||
|
||||
# Use pre-existing TLS credentials
|
||||
cargo run -p quicnprotochat-server -- \
|
||||
--tls-cert /etc/quicnprotochat/cert.der \
|
||||
--tls-key /etc/quicnprotochat/key.der
|
||||
cargo run -p quicproquo-server -- \
|
||||
--tls-cert /etc/quicproquo/cert.der \
|
||||
--tls-key /etc/quicproquo/key.der
|
||||
|
||||
# Via environment variables
|
||||
QUICNPROTOCHAT_LISTEN=0.0.0.0:9000 \
|
||||
QPQ_LISTEN=0.0.0.0:9000 \
|
||||
RUST_LOG=debug \
|
||||
cargo run -p quicnprotochat-server
|
||||
cargo run -p quicproquo-server
|
||||
```
|
||||
|
||||
### Production deployment
|
||||
|
||||
Set `QUICNPROTOCHAT_PRODUCTION=1` (or `true` / `yes`) so the server enforces production checks:
|
||||
Set `QPQ_PRODUCTION=1` (or `true` / `yes`) so the server enforces production checks:
|
||||
|
||||
- **Auth:** A non-empty `QUICNPROTOCHAT_AUTH_TOKEN` is required; the value `devtoken` is rejected.
|
||||
- **Auth:** A non-empty `QPQ_AUTH_TOKEN` is required; the value `devtoken` is rejected.
|
||||
- **TLS:** Existing cert and key files are required (auto-generation is disabled).
|
||||
- **SQL store:** When `--store-backend=sql`, a non-empty `QUICNPROTOCHAT_DB_KEY` is required. An empty key leaves the database unencrypted on disk and is not acceptable for production.
|
||||
- **SQL store:** When `--store-backend=sql`, a non-empty `QPQ_DB_KEY` is required. An empty key leaves the database unencrypted on disk and is not acceptable for production.
|
||||
|
||||
---
|
||||
|
||||
@@ -88,7 +88,7 @@ To use a certificate issued by a CA or a custom self-signed certificate:
|
||||
```
|
||||
2. Point the server at them:
|
||||
```bash
|
||||
cargo run -p quicnprotochat-server -- \
|
||||
cargo run -p quicproquo-server -- \
|
||||
--tls-cert cert.der \
|
||||
--tls-key key.der
|
||||
```
|
||||
@@ -128,7 +128,7 @@ The server persists its state to the data directory (`--data-dir`, default `data
|
||||
| `data/deliveries.bin` | `bincode`-serialised map of `(channelId, recipientKey)` to message queues |
|
||||
| `data/hybridkeys.bin` | `bincode`-serialised map of identity keys to hybrid (X25519 + ML-KEM-768) public keys |
|
||||
|
||||
Storage is implemented by the `FileBackedStore` in `crates/quicnprotochat-server/src/storage.rs`. Every mutation (upload, enqueue, fetch) flushes the entire map to disk synchronously. This is suitable for proof-of-concept workloads but not production traffic. See [Storage Backend](../internals/storage-backend.md) for details.
|
||||
Storage is implemented by the `FileBackedStore` in `crates/quicproquo-server/src/storage.rs`. Every mutation (upload, enqueue, fetch) flushes the entire map to disk synchronously. This is suitable for proof-of-concept workloads but not production traffic. See [Storage Backend](../internals/storage-backend.md) for details.
|
||||
|
||||
---
|
||||
|
||||
@@ -153,16 +153,16 @@ The server uses `tracing` with `tracing-subscriber` and respects the `RUST_LOG`
|
||||
|
||||
```bash
|
||||
# Default: info level
|
||||
RUST_LOG=info cargo run -p quicnprotochat-server
|
||||
RUST_LOG=info cargo run -p quicproquo-server
|
||||
|
||||
# Debug level for detailed RPC tracing
|
||||
RUST_LOG=debug cargo run -p quicnprotochat-server
|
||||
RUST_LOG=debug cargo run -p quicproquo-server
|
||||
|
||||
# Trace level for maximum verbosity
|
||||
RUST_LOG=trace cargo run -p quicnprotochat-server
|
||||
RUST_LOG=trace cargo run -p quicproquo-server
|
||||
|
||||
# Filter to specific crates
|
||||
RUST_LOG=quicnprotochat_server=debug,quinn=warn cargo run -p quicnprotochat-server
|
||||
RUST_LOG=quicproquo_server=debug,quinn=warn cargo run -p quicproquo-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -9,8 +9,8 @@ This page covers the server-side implementation of KeyPackage storage, the
|
||||
`Auth` struct validation logic, and the hybrid key endpoints.
|
||||
|
||||
**Sources:**
|
||||
- `crates/quicnprotochat-server/src/main.rs` (RPC handlers, auth validation)
|
||||
- `crates/quicnprotochat-server/src/storage.rs` (FileBackedStore)
|
||||
- `crates/quicproquo-server/src/main.rs` (RPC handlers, auth validation)
|
||||
- `crates/quicproquo-server/src/storage.rs` (FileBackedStore)
|
||||
- `schemas/node.capnp` (wire schema)
|
||||
|
||||
---
|
||||
@@ -148,8 +148,8 @@ Configured via CLI flags / environment variables:
|
||||
|
||||
| Flag / Env Var | Default | Purpose |
|
||||
|-----------------------------------|---------|---------|
|
||||
| `--auth-token` / `QUICNPROTOCHAT_AUTH_TOKEN` | None | Required bearer token. If unset, any non-empty token is accepted for version 1. |
|
||||
| `--allow-auth-v0` / `QUICNPROTOCHAT_ALLOW_AUTH_V0` | `true` | Whether to accept `auth.version=0` (legacy, unauthenticated) requests. |
|
||||
| `--auth-token` / `QPQ_AUTH_TOKEN` | None | Required bearer token. If unset, any non-empty token is accepted for version 1. |
|
||||
| `--allow-auth-v0` / `QPQ_ALLOW_AUTH_V0` | `true` | Whether to accept `auth.version=0` (legacy, unauthenticated) requests. |
|
||||
|
||||
### Version Semantics
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ recipient identity key and channel identifier. The DS exposes three operations
|
||||
through the `NodeService` RPC interface: `enqueue`, `fetch`, and `fetchWait`.
|
||||
|
||||
**Sources:**
|
||||
- `crates/quicnprotochat-server/src/main.rs` (RPC handlers)
|
||||
- `crates/quicnprotochat-server/src/storage.rs` (queue storage)
|
||||
- `crates/quicproquo-server/src/main.rs` (RPC handlers)
|
||||
- `crates/quicproquo-server/src/storage.rs` (queue storage)
|
||||
- `schemas/node.capnp` (wire schema)
|
||||
|
||||
---
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# GroupMember Lifecycle
|
||||
|
||||
The `GroupMember` struct in `quicnprotochat-core` is the core MLS state machine
|
||||
The `GroupMember` struct in `quicproquo-core` is the core MLS state machine
|
||||
that manages a single client's membership in an MLS group. It wraps an openmls
|
||||
`MlsGroup`, a persistent crypto backend, and the long-term Ed25519 identity
|
||||
keypair. Every MLS operation -- key package generation, group creation, member
|
||||
addition, joining, sending, and receiving -- flows through this struct.
|
||||
|
||||
**Source:** `crates/quicnprotochat-core/src/group.rs`
|
||||
**Source:** `crates/quicproquo-core/src/group.rs`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
MLS KeyPackages are single-use tokens that enable a group creator to add a new
|
||||
member. The KeyPackage contains the member's HPKE init public key, their MLS
|
||||
credential (Ed25519 public key), and a signature proving ownership. The
|
||||
quicnprotochat Authentication Service (AS) provides a simple upload/fetch
|
||||
quicproquo Authentication Service (AS) provides a simple upload/fetch
|
||||
interface for distributing KeyPackages between clients.
|
||||
|
||||
**Expiry and refresh:** KeyPackages are consumed on fetch (single-use). The server may also enforce a TTL (e.g. 24h). Clients should upload a fresh KeyPackage periodically or on demand so they remain invitable. The CLI provides `refresh-keypackage`: load existing state, generate a new KeyPackage, upload to the AS. See [Running the Client](../getting-started/running-the-client.md#refresh-keypackage).
|
||||
@@ -12,10 +12,10 @@ This page describes the end-to-end flow: from client-side generation through
|
||||
server-side storage to peer-side retrieval and consumption.
|
||||
|
||||
**Sources:**
|
||||
- `crates/quicnprotochat-core/src/group.rs` (client-side generation)
|
||||
- `crates/quicnprotochat-server/src/main.rs` (server-side handlers)
|
||||
- `crates/quicnprotochat-server/src/storage.rs` (server-side persistence)
|
||||
- `crates/quicnprotochat-client/src/lib.rs` (client-side RPC calls)
|
||||
- `crates/quicproquo-core/src/group.rs` (client-side generation)
|
||||
- `crates/quicproquo-server/src/main.rs` (server-side handlers)
|
||||
- `crates/quicproquo-server/src/storage.rs` (server-side persistence)
|
||||
- `crates/quicproquo-client/src/lib.rs` (client-side RPC calls)
|
||||
- `schemas/node.capnp` (wire schema)
|
||||
|
||||
---
|
||||
@@ -274,10 +274,10 @@ identity; `register-state` loads from (or initializes) a persistent state file.
|
||||
|
||||
```bash
|
||||
# Ephemeral registration (for testing)
|
||||
quicnprotochat register --server 127.0.0.1:7000
|
||||
qpq register --server 127.0.0.1:7000
|
||||
|
||||
# Persistent registration (production)
|
||||
quicnprotochat register-state --state alice.bin --server 127.0.0.1:7000
|
||||
qpq register-state --state alice.bin --server 127.0.0.1:7000
|
||||
```
|
||||
|
||||
Output:
|
||||
@@ -292,7 +292,7 @@ KeyPackage uploaded successfully.
|
||||
Fetches a peer's KeyPackage by their hex-encoded Ed25519 public key:
|
||||
|
||||
```bash
|
||||
quicnprotochat fetch-key --server 127.0.0.1:7000 7a3f...
|
||||
qpq fetch-key --server 127.0.0.1:7000 7a3f...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Storage Backend
|
||||
|
||||
quicnprotochat uses two storage backends: `FileBackedStore` on the server side
|
||||
quicproquo uses two storage backends: `FileBackedStore` on the server side
|
||||
for KeyPackages and delivery queues, and `DiskKeyStore` on the client side for
|
||||
MLS cryptographic key material. Both follow the same pattern: in-memory data
|
||||
structures backed by optional file persistence, with full serialization on every
|
||||
write.
|
||||
|
||||
**Sources:**
|
||||
- `crates/quicnprotochat-server/src/storage.rs` (FileBackedStore)
|
||||
- `crates/quicnprotochat-core/src/keystore.rs` (DiskKeyStore, StoreCrypto)
|
||||
- `crates/quicproquo-server/src/storage.rs` (FileBackedStore)
|
||||
- `crates/quicproquo-core/src/keystore.rs` (DiskKeyStore, StoreCrypto)
|
||||
|
||||
---
|
||||
|
||||
@@ -52,7 +52,7 @@ File paths:
|
||||
- `{dir}/hybridkeys.bin` -- Hybrid public keys
|
||||
|
||||
The default data directory is `data/`, configurable via `--data-dir` /
|
||||
`QUICNPROTOCHAT_DATA_DIR`.
|
||||
`QPQ_DATA_DIR`.
|
||||
|
||||
### Flush-on-Every-Write
|
||||
|
||||
@@ -233,7 +233,7 @@ fn keystore_path(state_path: &Path) -> PathBuf {
|
||||
}
|
||||
```
|
||||
|
||||
So `quicnprotochat-state.bin` produces a key store at `quicnprotochat-state.ks`.
|
||||
So `qpq-state.bin` produces a key store at `quicproquo-state.ks`.
|
||||
|
||||
### Persistence Format
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Introduction
|
||||
|
||||
**quicnprotochat** is a research-oriented, end-to-end encrypted group messaging system written in Rust. It layers the Messaging Layer Security protocol (MLS, [RFC 9420](https://datatracker.ietf.org/doc/rfc9420/)) on top of QUIC + TLS 1.3 transport (via [quinn](https://github.com/quinn-rs/quinn) and [rustls](https://github.com/rustls/rustls)), with all service RPCs and wire messages framed using [Cap'n Proto](https://capnproto.org/). The project exists to explore how modern transport encryption (QUIC), a formally specified group key agreement protocol (MLS), and a zero-copy serialisation format (Cap'n Proto) compose in practice -- and to provide a readable, auditable reference implementation for security researchers, protocol designers, and Rust developers who want to study or extend the design.
|
||||
**quicproquo** is a research-oriented, end-to-end encrypted group messaging system written in Rust. It layers the Messaging Layer Security protocol (MLS, [RFC 9420](https://datatracker.ietf.org/doc/rfc9420/)) on top of QUIC + TLS 1.3 transport (via [quinn](https://github.com/quinn-rs/quinn) and [rustls](https://github.com/rustls/rustls)), with all service RPCs and wire messages framed using [Cap'n Proto](https://capnproto.org/). The project exists to explore how modern transport encryption (QUIC), a formally specified group key agreement protocol (MLS), and a zero-copy serialisation format (Cap'n Proto) compose in practice -- and to provide a readable, auditable reference implementation for security researchers, protocol designers, and Rust developers who want to study or extend the design.
|
||||
|
||||
---
|
||||
|
||||
@@ -20,7 +20,7 @@ Each layer addresses a distinct concern:
|
||||
|
||||
1. **QUIC + TLS 1.3** provides authenticated, confidential transport with 0-RTT connection establishment and multiplexed streams. The server presents a TLS 1.3 certificate (self-signed by default); the client verifies it against a local trust anchor. ALPN negotiation uses the token `b"capnp"`.
|
||||
|
||||
2. **Cap'n Proto RPC** defines the wire schema for all service operations (KeyPackage upload/fetch, message enqueue/fetch, health probes). Schemas live in `schemas/*.capnp` and are compiled to Rust at build time. Because Cap'n Proto uses a pointer-based layout, messages can be read without an unpacking step -- though quicnprotochat currently uses the unpacked wire format for simplicity.
|
||||
2. **Cap'n Proto RPC** defines the wire schema for all service operations (KeyPackage upload/fetch, message enqueue/fetch, health probes). Schemas live in `schemas/*.capnp` and are compiled to Rust at build time. Because Cap'n Proto uses a pointer-based layout, messages can be read without an unpacking step -- though quicproquo currently uses the unpacked wire format for simplicity.
|
||||
|
||||
3. **MLS (RFC 9420)** provides the group key agreement layer. Each participant holds an Ed25519 identity keypair and generates single-use HPKE KeyPackages. The MLS epoch ratchet delivers forward secrecy and post-compromise security: compromising a member's state at epoch *n* does not reveal plaintext from epochs *< n* (forward secrecy) or *> n+1* (post-compromise security, once the compromised member updates).
|
||||
|
||||
@@ -49,7 +49,7 @@ For a deeper discussion of the cryptographic guarantees, threat model, and known
|
||||
|
||||
**Security researchers** studying how MLS composes with QUIC transport and Cap'n Proto framing. The codebase is intentionally small (four crates, ~2 500 lines of non-generated Rust) so that every cryptographic boundary is auditable.
|
||||
|
||||
**Protocol designers** evaluating MLS deployment patterns. quicnprotochat implements a concrete Authentication Service (AS) and Delivery Service (DS) pair, demonstrating single-use KeyPackage lifecycle, Welcome routing, and epoch advancement in a live system.
|
||||
**Protocol designers** evaluating MLS deployment patterns. quicproquo implements a concrete Authentication Service (AS) and Delivery Service (DS) pair, demonstrating single-use KeyPackage lifecycle, Welcome routing, and epoch advancement in a live system.
|
||||
|
||||
**Rust developers** looking for a working example of:
|
||||
|
||||
@@ -64,7 +64,7 @@ For a deeper discussion of the cryptographic guarantees, threat model, and known
|
||||
|
||||
| Section | What you will find |
|
||||
|---|---|
|
||||
| **[Comparison with Classical Protocols](design-rationale/protocol-comparison.md)** | **Why quicnprotochat? IRC+SSL, XMPP, Telegram vs. our design** |
|
||||
| **[Comparison with Classical Protocols](design-rationale/protocol-comparison.md)** | **Why quicproquo? IRC+SSL, XMPP, Telegram vs. our design** |
|
||||
| [Prerequisites](getting-started/prerequisites.md) | Toolchain and system dependencies |
|
||||
| [Building from Source](getting-started/building.md) | `cargo build`, Cap'n Proto codegen, troubleshooting |
|
||||
| [Running the Server](getting-started/running-the-server.md) | Server startup, configuration, TLS cert generation |
|
||||
@@ -82,7 +82,7 @@ For a deeper discussion of the cryptographic guarantees, threat model, and known
|
||||
|
||||
## Current status
|
||||
|
||||
quicnprotochat is a **proof of concept**. It has not been audited by a third party.
|
||||
quicproquo is a **proof of concept**. It has not been audited by a third party.
|
||||
|
||||
Known limitations:
|
||||
|
||||
@@ -99,4 +99,4 @@ For the full milestone tracker, see [Milestones](roadmap/milestones.md).
|
||||
|
||||
## License
|
||||
|
||||
quicnprotochat is released under the **MIT** license. See `LICENSE` in the repository root.
|
||||
quicproquo is released under the **MIT** license. See `LICENSE` in the repository root.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Cap'n Proto Serialisation and RPC
|
||||
|
||||
quicnprotochat uses [Cap'n Proto](https://capnproto.org/) for both message serialisation and remote procedure calls. The serialisation layer encodes structured messages (Envelopes, Auth tokens, delivery payloads) into a compact binary format. The RPC layer provides the client-server interface for the Authentication Service, Delivery Service, and health checks -- all exposed through a single `NodeService` interface.
|
||||
quicproquo uses [Cap'n Proto](https://capnproto.org/) for both message serialisation and remote procedure calls. The serialisation layer encodes structured messages (Envelopes, Auth tokens, delivery payloads) into a compact binary format. The RPC layer provides the client-server interface for the Authentication Service, Delivery Service, and health checks -- all exposed through a single `NodeService` interface.
|
||||
|
||||
This page covers why Cap'n Proto was chosen, how schemas are compiled, the owned `ParsedEnvelope` type, serialisation helpers, and ALPN integration with QUIC.
|
||||
|
||||
@@ -23,7 +23,7 @@ Cap'n Proto was selected for the following reasons:
|
||||
|
||||
3. **Canonical serialisation**: Cap'n Proto can produce deterministic byte representations of messages. This is critical for MLS, where Commits and KeyPackages must be signed -- the signature must cover exactly the same bytes that the verifier will see.
|
||||
|
||||
4. **Built-in async RPC**: The `capnp-rpc` crate provides a capability-based RPC system with promise pipelining. quicnprotochat uses it for the `NodeService` interface (KeyPackage upload/fetch, message enqueue/fetch, health checks, hybrid key operations). This avoids the need to hand-roll a request/response protocol.
|
||||
4. **Built-in async RPC**: The `capnp-rpc` crate provides a capability-based RPC system with promise pipelining. quicproquo uses it for the `NodeService` interface (KeyPackage upload/fetch, message enqueue/fetch, health checks, hybrid key operations). This avoids the need to hand-roll a request/response protocol.
|
||||
|
||||
5. **Compact wire format**: Cap'n Proto's wire format is more compact than JSON or XML and comparable to Protocol Buffers, with the advantage of no decode step.
|
||||
|
||||
@@ -41,7 +41,7 @@ schemas/
|
||||
|
||||
### build.rs
|
||||
|
||||
The `quicnprotochat-proto` crate compiles these schemas at build time via `build.rs`:
|
||||
The `quicproquo-proto` crate compiles these schemas at build time via `build.rs`:
|
||||
|
||||
```rust
|
||||
capnpc::CompilerCommand::new()
|
||||
@@ -63,7 +63,7 @@ Key details:
|
||||
|
||||
### Generated module inclusion
|
||||
|
||||
The generated code is spliced into the `quicnprotochat-proto` crate via `include!` macros:
|
||||
The generated code is spliced into the `quicproquo-proto` crate via `include!` macros:
|
||||
|
||||
```rust
|
||||
pub mod envelope_capnp {
|
||||
@@ -84,7 +84,7 @@ Consumers import types from these modules. For example, `node_capnp::node_servic
|
||||
|
||||
## The Envelope schema
|
||||
|
||||
The `Envelope` is the top-level wire message for all quicnprotochat traffic. Every frame exchanged between peers is serialised as an Envelope:
|
||||
The `Envelope` is the top-level wire message for all quicproquo traffic. Every frame exchanged between peers is serialised as an Envelope:
|
||||
|
||||
```capnp
|
||||
struct Envelope {
|
||||
@@ -114,7 +114,7 @@ The Delivery Service routes by `(groupId, msgType)` without inspecting `payload`
|
||||
|
||||
Cap'n Proto readers (`envelope_capnp::envelope::Reader`) borrow from the original byte buffer and cannot be sent across async task boundaries (`!Send`). This is a fundamental limitation of zero-copy reads.
|
||||
|
||||
To bridge this gap, `quicnprotochat-proto` defines `ParsedEnvelope`:
|
||||
To bridge this gap, `quicproquo-proto` defines `ParsedEnvelope`:
|
||||
|
||||
```rust
|
||||
pub struct ParsedEnvelope {
|
||||
@@ -256,11 +256,11 @@ MessagePack is untyped -- there is no schema file, and type errors are caught at
|
||||
|
||||
FlatBuffers supports zero-copy reads (like Cap'n Proto) but lacks a built-in RPC framework. The ecosystem and tooling are also less mature for Rust.
|
||||
|
||||
## Design constraints of `quicnprotochat-proto`
|
||||
## Design constraints of `quicproquo-proto`
|
||||
|
||||
The `quicnprotochat-proto` crate enforces three design constraints:
|
||||
The `quicproquo-proto` crate enforces three design constraints:
|
||||
|
||||
1. **No crypto**: Key material never enters this crate. All encryption and signing happens in `quicnprotochat-core`.
|
||||
1. **No crypto**: Key material never enters this crate. All encryption and signing happens in `quicproquo-core`.
|
||||
2. **No I/O**: Callers own the transport. This crate only converts between bytes and types.
|
||||
3. **No async**: Pure synchronous data-layer code. Async is the caller's responsibility.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Hybrid KEM: X25519 + ML-KEM-768
|
||||
|
||||
quicnprotochat implements a hybrid Key Encapsulation Mechanism that combines classical X25519 Diffie-Hellman with post-quantum ML-KEM-768 (FIPS 203). The hybrid construction ensures that the system remains secure even if one of the two components is broken: X25519 protects against failures in ML-KEM, and ML-KEM protects against quantum computers breaking X25519.
|
||||
quicproquo implements a hybrid Key Encapsulation Mechanism that combines classical X25519 Diffie-Hellman with post-quantum ML-KEM-768 (FIPS 203). The hybrid construction ensures that the system remains secure even if one of the two components is broken: X25519 protects against failures in ML-KEM, and ML-KEM protects against quantum computers breaking X25519.
|
||||
|
||||
The implementation lives in `quicnprotochat-core/src/hybrid_kem.rs`. It is fully implemented and tested but **not yet integrated into the MLS ciphersuite** -- integration is planned for the M5 milestone. Currently, the module can be used as a standalone envelope encryption layer to wrap MLS payloads in an outer post-quantum-resistant encryption before they transit the network.
|
||||
The implementation lives in `quicproquo-core/src/hybrid_kem.rs`. It is fully implemented and tested but **not yet integrated into the MLS ciphersuite** -- integration is planned for the M5 milestone. Currently, the module can be used as a standalone envelope encryption layer to wrap MLS payloads in an outer post-quantum-resistant encryption before they transit the network.
|
||||
|
||||
## Design approach
|
||||
|
||||
@@ -70,8 +70,8 @@ The two shared secrets are combined via HKDF-SHA256 with domain separation:
|
||||
ikm = X25519_shared_secret(32 bytes) || ML-KEM_shared_secret(32 bytes)
|
||||
salt = [] (empty)
|
||||
|
||||
key = HKDF-SHA256(salt, ikm, info="quicnprotochat-hybrid-v1", L=32)
|
||||
nonce = HKDF-SHA256(salt, ikm, info="quicnprotochat-hybrid-nonce-v1", L=12)
|
||||
key = HKDF-SHA256(salt, ikm, info="quicproquo-hybrid-v1", L=32)
|
||||
nonce = HKDF-SHA256(salt, ikm, info="quicproquo-hybrid-nonce-v1", L=12)
|
||||
```
|
||||
|
||||
The implementation in `derive_aead_material()`:
|
||||
@@ -85,10 +85,10 @@ fn derive_aead_material(x25519_ss: &[u8], mlkem_ss: &[u8]) -> (Key, Nonce) {
|
||||
let hk = Hkdf::<Sha256>::new(None, &ikm);
|
||||
|
||||
let mut key_bytes = Zeroizing::new([0u8; 32]);
|
||||
hk.expand(b"quicnprotochat-hybrid-v1", &mut *key_bytes).unwrap();
|
||||
hk.expand(b"quicproquo-hybrid-v1", &mut *key_bytes).unwrap();
|
||||
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
hk.expand(b"quicnprotochat-hybrid-nonce-v1", &mut nonce_bytes).unwrap();
|
||||
hk.expand(b"quicproquo-hybrid-nonce-v1", &mut nonce_bytes).unwrap();
|
||||
|
||||
(*Key::from_slice(&*key_bytes), *Nonce::from_slice(&nonce_bytes))
|
||||
}
|
||||
@@ -273,7 +273,7 @@ The AEAD nonce is derived deterministically from the shared secrets via HKDF. Si
|
||||
|
||||
## Further reading
|
||||
|
||||
- [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md) -- Broader discussion of quicnprotochat's PQ strategy.
|
||||
- [Post-Quantum Readiness](../cryptography/post-quantum-readiness.md) -- Broader discussion of quicproquo's PQ strategy.
|
||||
- [MLS (RFC 9420)](mls.md) -- The MLS layer that the hybrid KEM will wrap.
|
||||
- [Key Lifecycle and Zeroization](../cryptography/key-lifecycle.md) -- How hybrid key material is managed and cleared.
|
||||
- [Threat Model](../cryptography/threat-model.md) -- Where hybrid KEM fits in the overall threat model.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# MLS (RFC 9420)
|
||||
|
||||
The Messaging Layer Security protocol (RFC 9420) is the core cryptographic layer in quicnprotochat. It provides authenticated group key agreement with forward secrecy and post-compromise security -- properties that distinguish quicnprotochat from a simple transport-encrypted relay. This is the most detailed page in the Protocol Deep Dives section because MLS is the most complex layer in the stack.
|
||||
The Messaging Layer Security protocol (RFC 9420) is the core cryptographic layer in quicproquo. It provides authenticated group key agreement with forward secrecy and post-compromise security -- properties that distinguish quicproquo from a simple transport-encrypted relay. This is the most detailed page in the Protocol Deep Dives section because MLS is the most complex layer in the stack.
|
||||
|
||||
The implementation lives in `quicnprotochat-core/src/group.rs` and `quicnprotochat-core/src/keystore.rs`, using the `openmls 0.5` crate.
|
||||
The implementation lives in `quicproquo-core/src/group.rs` and `quicproquo-core/src/keystore.rs`, using the `openmls 0.5` crate.
|
||||
|
||||
## Background: what problem MLS solves
|
||||
|
||||
@@ -21,7 +21,7 @@ MLS takes a fundamentally different approach: it uses a **ratchet tree** (a bina
|
||||
|
||||
## Ciphersuite
|
||||
|
||||
quicnprotochat uses:
|
||||
quicproquo uses:
|
||||
|
||||
```text
|
||||
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
|
||||
@@ -38,7 +38,7 @@ This ciphersuite provides 128-bit classical security. Post-quantum protection is
|
||||
|
||||
## The `GroupMember` state machine
|
||||
|
||||
The central type is `GroupMember`, defined in `quicnprotochat-core/src/group.rs`. It wraps an openmls `MlsGroup`, a persistent crypto backend (`StoreCrypto`), and the user's long-term Ed25519 identity keypair.
|
||||
The central type is `GroupMember`, defined in `quicproquo-core/src/group.rs`. It wraps an openmls `MlsGroup`, a persistent crypto backend (`StoreCrypto`), and the user's long-term Ed25519 identity keypair.
|
||||
|
||||
### Lifecycle diagram
|
||||
|
||||
@@ -135,7 +135,7 @@ pub fn create_group(&mut self, group_id: &[u8]) -> Result<(), CoreError>
|
||||
Creates a new MLS group at epoch 0 with the caller as the sole member.
|
||||
|
||||
**Parameters:**
|
||||
- `group_id`: Any non-empty byte string. By convention, quicnprotochat uses the SHA-256 digest of a human-readable group name.
|
||||
- `group_id`: Any non-empty byte string. By convention, quicproquo uses the SHA-256 digest of a human-readable group name.
|
||||
|
||||
**What happens internally:**
|
||||
|
||||
@@ -259,7 +259,7 @@ Processes an incoming TLS-encoded MLS message.
|
||||
|
||||
## The `StoreCrypto` backend
|
||||
|
||||
The `StoreCrypto` struct (in `quicnprotochat-core/src/keystore.rs`) implements `OpenMlsCryptoProvider`, which openmls requires for all cryptographic operations:
|
||||
The `StoreCrypto` struct (in `quicproquo-core/src/keystore.rs`) implements `OpenMlsCryptoProvider`, which openmls requires for all cryptographic operations:
|
||||
|
||||
```rust
|
||||
pub struct StoreCrypto {
|
||||
@@ -318,11 +318,11 @@ KeyPackageIn::tls_deserialize(&mut bytes.as_ref())?
|
||||
|
||||
### Feature-gated methods
|
||||
|
||||
Several convenient methods (`into_welcome()`, `into_protocol_message()`) are feature-gated behind openmls feature flags that quicnprotochat does not enable. The workaround is to use `msg_in.extract()` and pattern-match on the `MlsMessageInBody` enum variants.
|
||||
Several convenient methods (`into_welcome()`, `into_protocol_message()`) are feature-gated behind openmls feature flags that quicproquo does not enable. The workaround is to use `msg_in.extract()` and pattern-match on the `MlsMessageInBody` enum variants.
|
||||
|
||||
### MlsGroup is not Send
|
||||
|
||||
`MlsGroup` holds internal state that may not be `Send` depending on the crypto backend. In quicnprotochat, `StoreCrypto` uses `RwLock` (which is `Send + Sync`), so `GroupMember` is `Send`. However, all MLS operations must use the same backend instance, so `GroupMember` should not be cloned across tasks.
|
||||
`MlsGroup` holds internal state that may not be `Send` depending on the crypto backend. In quicproquo, `StoreCrypto` uses `RwLock` (which is `Send + Sync`), so `GroupMember` is `Send`. However, all MLS operations must use the same backend instance, so `GroupMember` should not be cloned across tasks.
|
||||
|
||||
## Ratchet tree embedding
|
||||
|
||||
@@ -335,7 +335,7 @@ The trade-off:
|
||||
- **Pro**: No need for a separate tree distribution service or additional round-trips.
|
||||
- **Con**: Welcome messages grow with the group size (O(n log n) for a balanced tree of n members).
|
||||
|
||||
For quicnprotochat's target group sizes (2-100 members), this trade-off is acceptable.
|
||||
For quicproquo's target group sizes (2-100 members), this trade-off is acceptable.
|
||||
|
||||
## Wire format
|
||||
|
||||
@@ -386,7 +386,7 @@ The following sequence shows a complete Alice-and-Bob scenario, matching the `tw
|
||||
|
||||
## Credential model
|
||||
|
||||
quicnprotochat uses MLS `Basic` credentials. The credential body is the raw Ed25519 public key bytes (32 bytes), and the `signature_key` is the same public key:
|
||||
quicproquo uses MLS `Basic` credentials. The credential body is the raw Ed25519 public key bytes (32 bytes), and the `signature_key` is the same public key:
|
||||
|
||||
```rust
|
||||
let credential = Credential::new(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Protocol Layers Overview
|
||||
|
||||
quicnprotochat composes four distinct protocol layers into a single security stack. Each layer addresses a specific class of threat and delegates everything else to the layers above or below it. No single layer is sufficient on its own; the composition is what delivers end-to-end confidentiality, server authentication, forward secrecy, post-compromise security, and post-quantum resistance.
|
||||
quicproquo composes four distinct protocol layers into a single security stack. Each layer addresses a specific class of threat and delegates everything else to the layers above or below it. No single layer is sufficient on its own; the composition is what delivers end-to-end confidentiality, server authentication, forward secrecy, post-compromise security, and post-quantum resistance.
|
||||
|
||||
This page provides a high-level comparison and a suggested reading order. The deep-dive pages that follow contain implementation details drawn directly from the source code.
|
||||
|
||||
@@ -47,7 +47,7 @@ The pages in this section are ordered to build understanding incrementally:
|
||||
|
||||
1. **[QUIC + TLS 1.3](quic-tls.md)** -- Start here. This is the transport layer that every client-server connection uses. Understanding QUIC stream multiplexing and the TLS 1.3 handshake is prerequisite to understanding how Cap'n Proto RPC rides on top.
|
||||
|
||||
2. **[MLS (RFC 9420)](mls.md)** -- The core cryptographic innovation. MLS provides the group key agreement that makes quicnprotochat an E2E encrypted group messenger rather than just a transport-encrypted relay. This is the longest and most detailed page.
|
||||
2. **[MLS (RFC 9420)](mls.md)** -- The core cryptographic innovation. MLS provides the group key agreement that makes quicproquo an E2E encrypted group messenger rather than just a transport-encrypted relay. This is the longest and most detailed page.
|
||||
|
||||
3. **[Cap'n Proto Serialisation and RPC](capn-proto.md)** -- The serialisation and RPC layer that bridges MLS application data with the transport. Understanding the Envelope schema, the ParsedEnvelope owned type, and the NodeService RPC interface is essential for reading the server and client source code.
|
||||
|
||||
@@ -70,9 +70,9 @@ Each protocol layer maps to one or more workspace crates:
|
||||
|
||||
| Layer | Primary Crate | Source File(s) |
|
||||
|---|---|---|
|
||||
| QUIC + TLS 1.3 | `quicnprotochat-server`, `quicnprotochat-client` | `main.rs` (server and client entry points) |
|
||||
| Cap'n Proto | `quicnprotochat-proto` | `src/lib.rs`, `build.rs`, `schemas/*.capnp` |
|
||||
| MLS | `quicnprotochat-core` | `src/group.rs`, `src/keystore.rs` |
|
||||
| Hybrid KEM | `quicnprotochat-core` | `src/hybrid_kem.rs` |
|
||||
| QUIC + TLS 1.3 | `quicproquo-server`, `quicproquo-client` | `main.rs` (server and client entry points) |
|
||||
| Cap'n Proto | `quicproquo-proto` | `src/lib.rs`, `build.rs`, `schemas/*.capnp` |
|
||||
| MLS | `quicproquo-core` | `src/group.rs`, `src/keystore.rs` |
|
||||
| Hybrid KEM | `quicproquo-core` | `src/hybrid_kem.rs` |
|
||||
|
||||
For a full crate responsibility breakdown, see [Crate Responsibilities](../architecture/crate-responsibilities.md).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# QUIC + TLS 1.3
|
||||
|
||||
quicnprotochat uses QUIC (RFC 9000) with mandatory TLS 1.3 (RFC 9001) as its transport layer. This page explains how the `quinn` and `rustls` crates are integrated and what security properties the transport provides.
|
||||
quicproquo uses QUIC (RFC 9000) with mandatory TLS 1.3 (RFC 9001) as its transport layer. This page explains how the `quinn` and `rustls` crates are integrated and what security properties the transport provides.
|
||||
|
||||
## Why QUIC
|
||||
|
||||
@@ -14,16 +14,16 @@ QUIC provides several advantages over traditional TCP-based transports:
|
||||
|
||||
## Crate integration
|
||||
|
||||
quicnprotochat uses the following crates for QUIC and TLS:
|
||||
quicproquo uses the following crates for QUIC and TLS:
|
||||
|
||||
- **`quinn 0.11`** -- The async QUIC implementation for Tokio. Provides `Endpoint`, `Connection`, and bidirectional stream types.
|
||||
- **`quinn-proto 0.11`** -- The protocol-level types, including `QuicServerConfig` and `QuicClientConfig` wrappers that bridge `rustls` into `quinn`.
|
||||
- **`rustls 0.23`** -- The TLS implementation. quicnprotochat uses it in strict TLS 1.3 mode with no fallback to TLS 1.2.
|
||||
- **`rustls 0.23`** -- The TLS implementation. quicproquo uses it in strict TLS 1.3 mode with no fallback to TLS 1.2.
|
||||
- **`rcgen 0.13`** -- Self-signed certificate generation for development and testing.
|
||||
|
||||
### Server configuration
|
||||
|
||||
The server builds its QUIC endpoint configuration in `build_server_config()` (in `quicnprotochat-server/src/main.rs`):
|
||||
The server builds its QUIC endpoint configuration in `build_server_config()` (in `quicproquo-server/src/main.rs`):
|
||||
|
||||
```rust
|
||||
let mut tls = rustls::ServerConfig::builder_with_protocol_versions(&[&TLS13])
|
||||
@@ -37,7 +37,7 @@ Ok(ServerConfig::with_crypto(Arc::new(crypto)))
|
||||
|
||||
Key points:
|
||||
|
||||
1. **TLS 1.3 strict mode**: `builder_with_protocol_versions(&[&TLS13])` ensures no TLS 1.2 fallback. This is a hard requirement: TLS 1.2 lacks the 0-RTT and full forward secrecy guarantees that quicnprotochat relies on.
|
||||
1. **TLS 1.3 strict mode**: `builder_with_protocol_versions(&[&TLS13])` ensures no TLS 1.2 fallback. This is a hard requirement: TLS 1.2 lacks the 0-RTT and full forward secrecy guarantees that quicproquo relies on.
|
||||
|
||||
2. **No client certificate authentication**: `with_no_client_auth()` means the server does not verify client certificates at the TLS layer. Client authentication is handled at the application layer via Ed25519 identity keys and MLS credentials. This is a deliberate design choice -- MLS provides stronger authentication properties than TLS client certificates.
|
||||
|
||||
@@ -82,11 +82,11 @@ Because `capnp-rpc` uses `Rc<RefCell<>>` internally (making it `!Send`), all RPC
|
||||
|
||||
## Certificate trust model
|
||||
|
||||
quicnprotochat currently uses a **trust-on-first-use (TOFU)** model with self-signed certificates:
|
||||
quicproquo currently uses a **trust-on-first-use (TOFU)** model with self-signed certificates:
|
||||
|
||||
1. On first start, the server generates a self-signed certificate using `rcgen::generate_simple_self_signed` with SANs for `localhost`, `127.0.0.1`, and `::1`.
|
||||
2. The certificate and private key are persisted to disk as DER files (default: `data/server-cert.der` and `data/server-key.der`).
|
||||
3. Clients must obtain the server's certificate file out-of-band and reference it via the `--ca-cert` flag or `QUICNPROTOCHAT_CA_CERT` environment variable.
|
||||
3. Clients must obtain the server's certificate file out-of-band and reference it via the `--ca-cert` flag or `QPQ_CA_CERT` environment variable.
|
||||
|
||||
This model is adequate for development and single-server deployments. The roadmap includes:
|
||||
|
||||
@@ -136,18 +136,18 @@ The QUIC + TLS 1.3 layer provides:
|
||||
|
||||
| Environment Variable | CLI Flag | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `QUICNPROTOCHAT_LISTEN` | `--listen` | `0.0.0.0:7000` | QUIC listen address |
|
||||
| `QUICNPROTOCHAT_TLS_CERT` | `--tls-cert` | `data/server-cert.der` | TLS certificate path |
|
||||
| `QUICNPROTOCHAT_TLS_KEY` | `--tls-key` | `data/server-key.der` | TLS private key path |
|
||||
| `QUICNPROTOCHAT_DATA_DIR` | `--data-dir` | `data` | Persistent storage directory |
|
||||
| `QPQ_LISTEN` | `--listen` | `0.0.0.0:7000` | QUIC listen address |
|
||||
| `QPQ_TLS_CERT` | `--tls-cert` | `data/server-cert.der` | TLS certificate path |
|
||||
| `QPQ_TLS_KEY` | `--tls-key` | `data/server-key.der` | TLS private key path |
|
||||
| `QPQ_DATA_DIR` | `--data-dir` | `data` | Persistent storage directory |
|
||||
|
||||
### Client
|
||||
|
||||
| Environment Variable | CLI Flag | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `QUICNPROTOCHAT_CA_CERT` | `--ca-cert` | `data/server-cert.der` | Server certificate to trust |
|
||||
| `QUICNPROTOCHAT_SERVER_NAME` | `--server-name` | `localhost` | Expected TLS server name (must match certificate SAN) |
|
||||
| `QUICNPROTOCHAT_SERVER` | `--server` | `127.0.0.1:7000` | Server address (per-subcommand) |
|
||||
| `QPQ_CA_CERT` | `--ca-cert` | `data/server-cert.der` | Server certificate to trust |
|
||||
| `QPQ_SERVER_NAME` | `--server-name` | `localhost` | Expected TLS server name (must match certificate SAN) |
|
||||
| `QPQ_SERVER` | `--server` | `127.0.0.1:7000` | Server address (per-subcommand) |
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Auth, Devices, and Tokens
|
||||
|
||||
This page describes the authentication, device management, and authorisation
|
||||
design for quicnprotochat. It introduces account and device identities, gates
|
||||
design for quicproquo. It introduces account and device identities, gates
|
||||
server operations by authenticated identity, enforces rate and size limits, and
|
||||
binds MLS identity keys to accounts.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 1:1 Channel Design
|
||||
|
||||
This page describes the design for first-class 1:1 (direct message) channels in
|
||||
quicnprotochat. Channels provide per-conversation authorisation, MLS-encrypted
|
||||
quicproquo. Channels provide per-conversation authorisation, MLS-encrypted
|
||||
payloads, message retention with TTL eviction, and backward compatibility with
|
||||
the legacy delivery model.
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ Not strictly required for “operational” but expected for production deployme
|
||||
## 3. Roadmap and Documentation Updates
|
||||
|
||||
- **Milestones doc:** Mark M4 as **Complete** (CLI subcommands exist). Mark M6 as **Complete** (migrations + runner; server and client persistence in place). Leave M5 as **Next** and M7 as **Planned**.
|
||||
- **README:** Update milestone table to reflect M4 and M6 complete; add one line on migrations (e.g. “Server supports SQL migrations under `quicnprotochat-server/migrations/`”).
|
||||
- **README:** Update milestone table to reflect M4 and M6 complete; add one line on migrations (e.g. “Server supports SQL migrations under `quicproquo-server/migrations/`”).
|
||||
- **Migration convention:** Document in README or a dev doc: add new migrations as `NNN_name.sql`, add to `MIGRATIONS` in `sql_store.rs`, bump `SCHEMA_VERSION`.
|
||||
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Future Research Directions
|
||||
|
||||
This page catalogues technologies and research directions that could strengthen
|
||||
quicnprotochat beyond the current [milestone plan](milestones.md). Each entry
|
||||
quicproquo beyond the current [milestone plan](milestones.md). Each entry
|
||||
includes a brief description, the problem it solves, relevant crates or
|
||||
specifications, and how it maps to the project architecture.
|
||||
|
||||
@@ -21,7 +21,7 @@ delivery.
|
||||
**Solution:** [LibP2P](https://libp2p.io/) and [iroh](https://iroh.computer/)
|
||||
(from n0) provide peer discovery, NAT traversal (hole-punching), and relay
|
||||
fallback. iroh is particularly interesting because it is Rust-native and built on
|
||||
QUIC, aligning with quicnprotochat's existing transport layer.
|
||||
QUIC, aligning with quicproquo's existing transport layer.
|
||||
|
||||
**Architecture impact:** Move from pure client-server to a hybrid topology where
|
||||
peers communicate directly when possible and fall back to server relay when NAT
|
||||
@@ -68,7 +68,7 @@ significantly, so this should be optional.
|
||||
|
||||
### SQLCipher / libsql (Turso)
|
||||
|
||||
**Problem:** At M6, quicnprotochat needs persistent storage for group state, key
|
||||
**Problem:** At M6, quicproquo needs persistent storage for group state, key
|
||||
material, and message queues. Storing private keys in a plaintext SQLite database
|
||||
is insufficient.
|
||||
|
||||
@@ -129,7 +129,7 @@ vulnerable to harvest-now-decrypt-later attacks.
|
||||
hybrid Ed25519 + ML-DSA-65 for credential signatures. The `ml-kem` crate is
|
||||
already vendored in the workspace.
|
||||
|
||||
**Architecture impact:** Custom `OpenMlsCryptoProvider` in `quicnprotochat-core`
|
||||
**Architecture impact:** Custom `OpenMlsCryptoProvider` in `quicproquo-core`
|
||||
implementing the hybrid combiner. This is the M7 milestone -- see
|
||||
[Milestones](milestones.md#m7----post-quantum-planned) and
|
||||
[Hybrid KEM](../protocol-layers/hybrid-kem.md).
|
||||
@@ -202,7 +202,7 @@ DID URIs. The server resolves DIDs to public keys for routing.
|
||||
|
||||
### OPAQUE (aPAKE)
|
||||
|
||||
**Problem:** If quicnprotochat adds password-based account registration, the
|
||||
**Problem:** If quicproquo adds password-based account registration, the
|
||||
server must never see the password -- not even a hash.
|
||||
|
||||
**Solution:** [OPAQUE](https://datatracker.ietf.org/doc/rfc9497/) is an
|
||||
@@ -253,7 +253,7 @@ admin could require proof of organization membership before allowing join.
|
||||
**Problem:** A single server is a single point of failure and a single point of
|
||||
trust. Users on different servers cannot communicate.
|
||||
|
||||
**Solution:** Federation allows multiple quicnprotochat servers to exchange
|
||||
**Solution:** Federation allows multiple quicproquo servers to exchange
|
||||
messages, similar to [Matrix](https://matrix.org/) homeserver federation. Each
|
||||
server manages its own users and relays messages to peer servers.
|
||||
|
||||
@@ -345,10 +345,10 @@ the user base for testing and demonstration.
|
||||
|
||||
**Solution:** [Tauri](https://tauri.app/) or [Dioxus](https://dioxuslabs.com/)
|
||||
provide native cross-platform GUI frameworks in Rust. The
|
||||
`quicnprotochat-core` crate can be shared directly with the GUI client.
|
||||
`quicproquo-core` crate can be shared directly with the GUI client.
|
||||
|
||||
**Architecture impact:** Add a `quicnprotochat-gui` crate that depends on
|
||||
`quicnprotochat-core` and `quicnprotochat-proto`. The GUI drives the same
|
||||
**Architecture impact:** Add a `quicproquo-gui` crate that depends on
|
||||
`quicproquo-core` and `quicproquo-proto`. The GUI drives the same
|
||||
`GroupMember` and RPC logic as the CLI client.
|
||||
|
||||
**Crates:** `tauri`, `dioxus`
|
||||
@@ -361,7 +361,7 @@ provide native cross-platform GUI frameworks in Rust. The
|
||||
[diplomat](https://github.com/nickelc/diplomat) generate idiomatic Swift and
|
||||
Kotlin bindings from Rust definitions.
|
||||
|
||||
**Architecture impact:** Expose `quicnprotochat-core` through a C-compatible FFI
|
||||
**Architecture impact:** Expose `quicproquo-core` through a C-compatible FFI
|
||||
layer. Mobile apps call into the Rust crypto and protocol logic.
|
||||
|
||||
**Crates:** `uniffi`, `diplomat`
|
||||
@@ -387,10 +387,10 @@ considering the current state of the codebase and the [milestone plan](milestone
|
||||
|
||||
| Priority | Technology | Why | Unlocks |
|
||||
|----------|-----------|-----|---------|
|
||||
| 1 | **Post-quantum hybrid KEM** | `ml-kem` is already vendored in the workspace. Completing the hybrid `OpenMlsCryptoProvider` makes quicnprotochat one of the first PQ MLS implementations. | M7 |
|
||||
| 1 | **Post-quantum hybrid KEM** | `ml-kem` is already vendored in the workspace. Completing the hybrid `OpenMlsCryptoProvider` makes quicproquo one of the first PQ MLS implementations. | M7 |
|
||||
| 2 | **SQLCipher persistence** | Encrypted-at-rest storage is the prerequisite for multi-device support, offline usage, and server restart survival. | M6 |
|
||||
| 3 | **OPAQUE auth** | Zero-knowledge password authentication is a massive security uplift for the account system. The server never sees or stores passwords. | Phase 3 (authz) |
|
||||
| 4 | **iroh / LibP2P** | NAT traversal and optional P2P mesh makes quicnprotochat deployable without centralised infrastructure. Aligns with the existing QUIC transport. | Beyond M7 |
|
||||
| 4 | **iroh / LibP2P** | NAT traversal and optional P2P mesh makes quicproquo deployable without centralised infrastructure. Aligns with the existing QUIC transport. | Beyond M7 |
|
||||
| 5 | **Sealed Sender + PIR** | Content encryption is table stakes. Metadata resistance (hiding who talks to whom) is the frontier of private messaging research. | Beyond M7 |
|
||||
|
||||
---
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Milestone Tracker
|
||||
|
||||
This page tracks the project milestones for quicnprotochat, from initial transport
|
||||
This page tracks the project milestones for quicproquo, from initial transport
|
||||
layer through post-quantum cryptography. Each milestone produces production-ready,
|
||||
tested, deployable code -- see [Coding Standards](../contributing/coding-standards.md)
|
||||
for what that means in practice.
|
||||
@@ -29,13 +29,13 @@ typed Cap'n Proto frames.
|
||||
**Deliverables:**
|
||||
|
||||
- `schemas/envelope.capnp`: `Envelope` struct with `MsgType` enum (Ping/Pong at this stage)
|
||||
- `quicnprotochat-proto`: `build.rs` invoking `capnpc`, generated type re-exports,
|
||||
- `quicproquo-proto`: `build.rs` invoking `capnpc`, generated type re-exports,
|
||||
canonical serialisation helpers
|
||||
- `quicnprotochat-core`: Ed25519 identity keypair generation,
|
||||
- `quicproquo-core`: Ed25519 identity keypair generation,
|
||||
Cap'n Proto frame codec (Tokio `Encoder`/`Decoder`)
|
||||
- `quicnprotochat-server`: QUIC listener with TLS 1.3 (quinn/rustls), Ping to Pong
|
||||
- `quicproquo-server`: QUIC listener with TLS 1.3 (quinn/rustls), Ping to Pong
|
||||
handler, one tokio task per connection
|
||||
- `quicnprotochat-client`: connects over QUIC, sends Ping, receives Pong, exits 0
|
||||
- `quicproquo-client`: connects over QUIC, sends Ping, receives Pong, exits 0
|
||||
- Integration test: server and client in same test binary using `tokio::spawn`
|
||||
- `docker-compose.yml` running the server
|
||||
|
||||
@@ -54,10 +54,10 @@ via Cap'n Proto RPC.
|
||||
|
||||
- `schemas/auth.capnp`: `AuthenticationService` interface (`uploadKeyPackage`,
|
||||
`fetchKeyPackage`)
|
||||
- `quicnprotochat-core`: Ed25519 identity keypair generation, MLS KeyPackage
|
||||
- `quicproquo-core`: Ed25519 identity keypair generation, MLS KeyPackage
|
||||
generation via `openmls`
|
||||
- `quicnprotochat-server`: AS RPC server with `DashMap` store, atomic consume-on-fetch
|
||||
- `quicnprotochat-client`: `register-state` and `fetch-key` CLI subcommands
|
||||
- `quicproquo-server`: AS RPC server with `DashMap` store, atomic consume-on-fetch
|
||||
- `quicproquo-client`: `register-state` and `fetch-key` CLI subcommands
|
||||
- Integration test: Alice uploads KeyPackage, Bob fetches it, fingerprints match
|
||||
|
||||
**Tests:** auth\_service.rs integration tests (upload, fetch, consume semantics).
|
||||
@@ -97,7 +97,7 @@ group\_id lifecycle, MLS integration.
|
||||
3. **openmls 0.5 API gotchas.** Several `openmls` methods changed signatures
|
||||
between 0.4 and 0.5 (e.g., `MlsGroup::new` vs `MlsGroup::new_with_group_id`,
|
||||
`BasicCredential::new` taking `Vec<u8>` directly). These differences are
|
||||
documented inline in `quicnprotochat-core/src/group.rs`.
|
||||
documented inline in `quicproquo-core/src/group.rs`.
|
||||
|
||||
**Branch:** `feat/m1-noise-transport`
|
||||
|
||||
@@ -143,13 +143,13 @@ providing post-quantum confidentiality for all group key material.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- Custom `OpenMlsCryptoProvider` with hybrid KEM in `quicnprotochat-core`
|
||||
- Custom `OpenMlsCryptoProvider` with hybrid KEM in `quicproquo-core`
|
||||
- Hybrid shared secret derivation:
|
||||
|
||||
```
|
||||
SharedSecret = HKDF-SHA256(
|
||||
ikm = X25519_ss || ML-KEM-768_ss,
|
||||
info = "quicnprotochat-hybrid-v1",
|
||||
info = "quicproquo-hybrid-v1",
|
||||
len = 32
|
||||
)
|
||||
```
|
||||
|
||||
@@ -21,7 +21,7 @@ The following legacy behaviour has been removed; only current behaviour is suppo
|
||||
|
||||
| Task | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| **Ciphersuite allowlist** | **Done** | Server rejects KeyPackages whose ciphersuite is not `MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519`. See `quicnprotochat_core::validate_keypackage_ciphersuite` and `upload_key_package` (E021). |
|
||||
| **Ciphersuite allowlist** | **Done** | Server rejects KeyPackages whose ciphersuite is not `MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519`. See `quicproquo_core::validate_keypackage_ciphersuite` and `upload_key_package` (E021). |
|
||||
| **ALPN enforcement** | **Done** | Server TLS config sets `alpn_protocols = [b"capnp"]`; handshake completes only if client offers `capnp`. |
|
||||
| **Connection draining** | **Done** | On `Ctrl+C`, server calls `endpoint.close(0, b"server shutdown")` and exits the accept loop. |
|
||||
| **Wire versioning** | **Done** | `enqueue`, `fetch`, `fetchWait` require `version == CURRENT_WIRE_VERSION` (1). Other RPCs use auth version. |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Production Readiness WBS
|
||||
|
||||
This page defines the work breakdown structure (WBS) for taking quicnprotochat
|
||||
This page defines the work breakdown structure (WBS) for taking quicproquo
|
||||
from a proof-of-concept to a production-hardened system. It covers feature scope,
|
||||
security policy, phased delivery, and a planning checklist.
|
||||
|
||||
@@ -11,7 +11,7 @@ document focuses on the cross-cutting concerns that span multiple milestones.
|
||||
|
||||
## Feature Scope (Must-Have)
|
||||
|
||||
These are the feature areas that must be addressed before quicnprotochat can be
|
||||
These are the feature areas that must be addressed before quicproquo can be
|
||||
considered production-ready. Each area maps to one or more milestones or phases
|
||||
in the WBS below.
|
||||
|
||||
@@ -30,7 +30,7 @@ in the WBS below.
|
||||
|
||||
## Security Plan (By Design)
|
||||
|
||||
quicnprotochat follows a security-by-design philosophy. The standards below are
|
||||
quicproquo follows a security-by-design philosophy. The standards below are
|
||||
non-negotiable -- see [Coding Standards](../contributing/coding-standards.md) for
|
||||
how they are enforced in code.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
**Schema file:** `schemas/envelope.capnp`
|
||||
**File ID:** `@0xe4a7f2c8b1d63509`
|
||||
|
||||
The Envelope is the legacy top-level wire message used in M1 for all quicnprotochat traffic. Every frame exchanged between peers was serialised as an Envelope, with the Delivery Service routing by `(groupId, msgType)` without inspecting the payload.
|
||||
The Envelope is the legacy top-level wire message used in M1 for all quicproquo traffic. Every frame exchanged between peers was serialised as an Envelope, with the Delivery Service routing by `(groupId, msgType)` without inspecting the payload.
|
||||
|
||||
> **Note:** The Envelope is the M1-era framing format. The current M3+ architecture uses Cap'n Proto RPC directly via the [NodeService](node-service-schema.md) interface. The Envelope schema remains in the codebase for backward compatibility and for use in integration tests.
|
||||
|
||||
@@ -12,7 +12,7 @@ The Envelope is the legacy top-level wire message used in M1 for all quicnprotoc
|
||||
## Full schema listing
|
||||
|
||||
```capnp
|
||||
# envelope.capnp -- top-level wire message for all quicnprotochat traffic.
|
||||
# envelope.capnp -- top-level wire message for all quicproquo traffic.
|
||||
#
|
||||
# Every frame is serialised as an Envelope.
|
||||
# The Delivery Service routes by (groupId, msgType) without inspecting payload.
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
**Schema file:** `schemas/node.capnp`
|
||||
**File ID:** `@0xd5ca5648a9cc1c28`
|
||||
|
||||
The `NodeService` interface is the unified Cap'n Proto RPC surface that every quicnprotochat client talks to. It combines the Authentication Service and Delivery Service into a single interface, adds long-polling support (`fetchWait`), a health probe (`health`), and hybrid KEM key management. Every method that mutates state or accesses per-user data accepts an `Auth` struct for versioned authentication.
|
||||
The `NodeService` interface is the unified Cap'n Proto RPC surface that every quicproquo client talks to. It combines the Authentication Service and Delivery Service into a single interface, adds long-polling support (`fetchWait`), a health probe (`health`), and hybrid KEM key management. Every method that mutates state or accesses per-user data accepts an `Auth` struct for versioned authentication.
|
||||
|
||||
---
|
||||
|
||||
## Full schema listing
|
||||
|
||||
```capnp
|
||||
# node.capnp -- Unified quicnprotochat node RPC interface.
|
||||
# node.capnp -- Unified quicproquo node RPC interface.
|
||||
#
|
||||
# Combines Authentication and Delivery operations into a single service.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Wire Format Overview
|
||||
|
||||
This section documents the serialisation pipeline that transforms application-level data structures into encrypted bytes on the wire. Every byte exchanged between quicnprotochat clients and the server passes through this pipeline, so understanding it is prerequisite to reading the protocol deep dives or the server/client source code.
|
||||
This section documents the serialisation pipeline that transforms application-level data structures into encrypted bytes on the wire. Every byte exchanged between quicproquo clients and the server passes through this pipeline, so understanding it is prerequisite to reading the protocol deep dives or the server/client source code.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user