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

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

11 KiB

Delivery and Keys Schema

Proto files: proto/qpc/v1/delivery.proto, proto/qpc/v1/keys.proto Package: qpc.v1 Method IDs: 200-205 (delivery), 300-304 (key packages and hybrid keys), 510-520 (key transparency)

This page documents the Protobuf message definitions for the delivery service (store-and-forward message relay) and the key management service (MLS KeyPackages, hybrid post-quantum keys, and key transparency).


delivery.proto

The delivery service is a store-and-forward relay. It is intentionally MLS-unaware: all payloads are opaque byte strings routed by recipient key and channel ID. The server never inspects or decrypts message content.

Full proto listing

syntax = "proto3";
package qpc.v1;

// Delivery service: enqueue, fetch, peek, ack, batch (6 methods).
// Method IDs: 200-205.

message Envelope {
  uint64 seq = 1;
  bytes data = 2;
}

message EnqueueRequest {
  bytes recipient_key = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  uint32 ttl_secs = 4;
  // Client-generated idempotency key (16 bytes, UUID v7).
  // Server deduplicates enqueue requests with the same message_id within a TTL window.
  bytes message_id = 5;
}

message EnqueueResponse {
  uint64 seq = 1;
  bytes delivery_proof = 2;
  // True if this was a duplicate enqueue (message_id already seen).
  bool duplicate = 3;
}

message FetchRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint32 limit = 3;
  // Device ID for multi-device scoping.
  bytes device_id = 4;
}

message FetchResponse {
  repeated Envelope payloads = 1;
}

message FetchWaitRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint64 timeout_ms = 3;
  uint32 limit = 4;
  bytes device_id = 5;
}

message FetchWaitResponse {
  repeated Envelope payloads = 1;
}

message PeekRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint32 limit = 3;
  bytes device_id = 4;
}

message PeekResponse {
  repeated Envelope payloads = 1;
}

message AckRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint64 seq_up_to = 3;
  bytes device_id = 4;
}

message AckResponse {}

message BatchEnqueueRequest {
  repeated bytes recipient_keys = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  uint32 ttl_secs = 4;
  bytes message_id = 5;
}

message BatchEnqueueResponse {
  repeated uint64 seqs = 1;
}

Envelope

The Envelope wrapper is returned by fetch, peek, and fetch-wait operations.

Field Type Description
seq uint64 Server-assigned monotonic sequence number for ordering and acknowledgment.
data bytes The original payload bytes submitted at enqueue time.

Enqueue (ID 200)

Appends an opaque payload to a recipient's queue. Returns immediately.

Request:

Field Type Description
recipient_key bytes Recipient's Ed25519 identity public key (32 bytes). Primary queue index.
payload bytes Opaque byte string. Typically a TLS-encoded MLS ciphertext blob.
channel_id bytes Channel identifier (16-byte UUID v7 recommended). Empty = default channel.
ttl_secs uint32 Time-to-live in seconds. Server garbage-collects expired messages. 0 = server default.
message_id bytes Client-generated idempotency key (16 bytes, UUID v7). Server deduplicates within the TTL window.

Response:

Field Type Description
seq uint64 Server-assigned sequence number for this message.
delivery_proof bytes Cryptographic proof of delivery (reserved for future use).
duplicate bool true if this message_id was already seen within the TTL window; the payload was not stored again.

Fetch (ID 201)

Returns and retains queued messages up to limit. Does not remove messages from the queue; use Ack to advance the read cursor.

Request:

Field Type Description
recipient_key bytes Recipient's Ed25519 identity public key (32 bytes).
channel_id bytes Channel identifier. Must match the value used at enqueue time.
limit uint32 Maximum number of envelopes to return. 0 = server default.
device_id bytes Optional device identifier for multi-device queue scoping.

Response:

Field Type Description
payloads repeated Envelope Messages in FIFO order. Empty list if no messages are pending.

FetchWait (ID 202)

Long-poll variant of Fetch. Blocks on the server until messages arrive or timeout_ms elapses.

Request:

Field Type Description
recipient_key bytes Recipient's Ed25519 identity public key (32 bytes).
channel_id bytes Channel identifier.
timeout_ms uint64 Maximum wait time in milliseconds. 0 = return immediately (equivalent to Fetch).
limit uint32 Maximum number of envelopes to return.
device_id bytes Optional device identifier.

Response: Same as FetchResponse.

FetchWait eliminates polling latency: the server holds the RPC open until a Notify is signalled by a concurrent Enqueue call, or until timeout_ms expires.

Peek (ID 203)

Non-destructive read. Returns messages without removing them and without advancing the acknowledgment cursor.

Request / Response: Same field layout as FetchRequest / FetchResponse.

Peek is useful for inspecting pending messages without marking them as delivered.

Ack (ID 204)

Advances the delivery cursor, removing all messages with seq <= seq_up_to from the queue.

Request:

Field Type Description
recipient_key bytes Recipient's Ed25519 identity public key (32 bytes).
channel_id bytes Channel identifier.
seq_up_to uint64 All messages with sequence number <= this value are removed.
device_id bytes Optional device identifier.

Response: Empty (AckResponse {}).

BatchEnqueue (ID 205)

Fan-out: enqueues the same payload to multiple recipients in a single RPC call.

Request:

Field Type Description
recipient_keys repeated bytes List of recipient Ed25519 identity public keys.
payload bytes Opaque payload, delivered identically to all recipients.
channel_id bytes Channel identifier.
ttl_secs uint32 Time-to-live in seconds.
message_id bytes Idempotency key (16 bytes).

Response:

Field Type Description
seqs repeated uint64 Server-assigned sequence numbers, one per recipient_key, in the same order.

keys.proto

Key management for MLS KeyPackages, hybrid post-quantum keys, and key transparency audit.

Full proto listing

syntax = "proto3";
package qpc.v1;

// Key package + hybrid key CRUD (5 methods).
// Method IDs: 300-304.

message UploadKeyPackageRequest {
  bytes identity_key = 1;
  bytes package = 2;
}

message UploadKeyPackageResponse {
  bytes fingerprint = 1;
}

message FetchKeyPackageRequest {
  bytes identity_key = 1;
}

message FetchKeyPackageResponse {
  bytes package = 1;
}

message UploadHybridKeyRequest {
  bytes identity_key = 1;
  bytes hybrid_public_key = 2;
}

message UploadHybridKeyResponse {}

message FetchHybridKeyRequest {
  bytes identity_key = 1;
}

message FetchHybridKeyResponse {
  bytes hybrid_public_key = 1;
}

message FetchHybridKeysRequest {
  repeated bytes identity_keys = 1;
}

message FetchHybridKeysResponse {
  repeated bytes keys = 1;
}

// Key revocation (method ID 510).
message RevokeKeyRequest {
  bytes identity_key = 1;
  string reason = 2; // "compromised", "superseded", "user_revoked"
}

message RevokeKeyResponse {
  bool success = 1;
  uint64 leaf_index = 2;
}

// Check revocation status (method ID 511).
message CheckRevocationRequest {
  bytes identity_key = 1;
}

message CheckRevocationResponse {
  bool revoked = 1;
  string reason = 2;
  uint64 timestamp_ms = 3;
}

// KT audit log retrieval (method ID 520).
message AuditKeyTransparencyRequest {
  uint64 start = 1;
  uint64 end = 2;
}

message AuditKeyTransparencyResponse {
  repeated LogEntry entries = 1;
  uint64 tree_size = 2;
  bytes root = 3;
}

message LogEntry {
  uint64 index = 1;
  bytes leaf_hash = 2;
}

UploadKeyPackage (ID 300)

Uploads a single-use MLS KeyPackage. KeyPackages are stored in a FIFO queue per identity; each is consumed once by FetchKeyPackage.

Field Type Description
identity_key bytes Uploader's Ed25519 identity public key (32 bytes). Index key for the queue.
package bytes openmls-serialised KeyPackage (bincode format, as required by DiskKeyStore).

Response: fingerprint -- SHA-256 digest of the stored package (32 bytes). Callers should record this to detect tampering.

FetchKeyPackage (ID 301)

Fetches and atomically removes one KeyPackage for the given identity. Returns empty bytes if no packages are stored. The removal is atomic; concurrent fetches will not receive the same package.

UploadHybridKey (ID 302)

Uploads the client's hybrid (X25519 + ML-KEM-768) public key. Unlike KeyPackages, hybrid keys are not single-use -- each identity stores exactly one, overwriting the previous value.

Field Type Description
identity_key bytes Uploader's Ed25519 identity public key (32 bytes).
hybrid_public_key bytes Concatenated X25519 public key (32 bytes) + ML-KEM-768 encapsulation key.

FetchHybridKey (ID 303)

Fetches a single peer's hybrid public key. Non-destructive.

FetchHybridKeys (ID 304)

Batch variant of FetchHybridKey. Returns one key per input identity key, in the same order. Missing keys are returned as empty bytes at the corresponding index.

RevokeKey (ID 510)

Revokes an identity key by appending a revocation entry to the key transparency Merkle log.

Field Type Description
identity_key bytes Identity key to revoke (32 bytes).
reason string One of: "compromised", "superseded", "user_revoked".

Response: leaf_index is the index of the revocation entry in the KT Merkle log.

CheckRevocation (ID 511)

Checks whether an identity key has been revoked.

Response fields: revoked (bool), reason (string), timestamp_ms (uint64 unix milliseconds of the revocation event).

AuditKeyTransparency (ID 520)

Returns a range of entries from the key transparency append-only Merkle log.

Field Type Description
start uint64 First leaf index (inclusive).
end uint64 Last leaf index (exclusive). 0 = up to current tree size.

Response: entries (list of LogEntry), tree_size (current log size), root (Merkle root hash).


Further reading