Delete 8 Noise-specific documentation pages (noise-xx.md,
transport-keys.md, adr-001/003/006, framing-codec.md) and update
~30 remaining wiki pages to reflect QUIC+TLS as the sole transport.
Remove obsolete Noise-based integration tests (auth_service.rs,
mls_group.rs). Code-side Noise removal was done in f334ed3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.8 KiB
Envelope Schema
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.
Note: The Envelope is the M1-era framing format. The current M3+ architecture uses Cap'n Proto RPC directly via the NodeService interface. The Envelope schema remains in the codebase for backward compatibility and for use in integration tests.
Full schema listing
# envelope.capnp -- top-level wire message for all quicnprotochat traffic.
#
# Every frame is serialised as an Envelope.
# The Delivery Service routes by (groupId, msgType) without inspecting payload.
#
# Field sizing rationale:
# groupId / senderId : 32 bytes -- SHA-256 digest
# payload : opaque -- MLS blob or control data
# timestampMs : UInt64 -- unix epoch milliseconds; sufficient until year 292M
#
# ID generated with: capnp id
@0xe4a7f2c8b1d63509;
struct Envelope {
# Message type discriminant -- determines how payload is interpreted.
msgType @0 :MsgType;
# 32-byte SHA-256 digest of the group name.
# The Delivery Service uses this as its routing key.
# Zero-filled for point-to-point control messages (ping, keyPackageUpload, etc.).
groupId @1 :Data;
# 32-byte SHA-256 digest of the sender's Ed25519 identity public key.
senderId @2 :Data;
# Opaque payload. Interpretation is determined by msgType.
payload @3 :Data;
# Unix timestamp in milliseconds at the time of send.
timestampMs @4 :UInt64;
enum MsgType {
ping @0;
pong @1;
keyPackageUpload @2;
keyPackageFetch @3;
keyPackageResponse @4;
mlsWelcome @5;
mlsCommit @6;
mlsApplication @7;
error @8;
}
}
Field-by-field analysis
msgType @0 :MsgType
A 16-bit enum discriminant (Cap'n Proto enums are encoded as UInt16). Determines how the payload field should be interpreted. The discriminant is the first field in the struct for efficient dispatch: a router can read the first two bytes of the struct section to decide how to handle the message without parsing any pointer fields.
groupId @1 :Data
A 32-byte Data field containing the SHA-256 digest of the group name. The Delivery Service uses this as its primary routing key when the Envelope-based protocol is active.
Sizing rationale: SHA-256 produces a 32-byte (256-bit) digest. This is stored as a variable-length Data field rather than a fixed-size blob because Cap'n Proto does not have a fixed-size array type. Implementations must validate that the field contains exactly 32 bytes.
Special case: For point-to-point control messages (ping, pong, keyPackageUpload, keyPackageFetch), the groupId is zero-filled (32 zero bytes) because these messages are not associated with any group.
senderId @2 :Data
A 32-byte Data field containing the SHA-256 digest of the sender's Ed25519 identity public key. This allows the receiver to identify the sender without inspecting the MLS-layer credentials.
Sizing rationale: Same as groupId -- SHA-256 digest, 32 bytes.
payload @3 :Data
An opaque byte string whose interpretation depends on msgType.
timestampMs @4 :UInt64
Unix epoch timestamp in milliseconds, set by the sender at the time of send. Encoded as a UInt64, which provides sufficient range until approximately year 292,000,000 -- effectively unlimited for practical purposes.
The timestamp is sender-asserted and not authenticated by the server. Receivers should treat it as advisory (for display ordering) rather than authoritative.
MsgType enum
The MsgType enum defines nine message types. Each variant determines how the payload field is interpreted:
| Ordinal | Variant | Payload Contents | Direction |
|---|---|---|---|
| 0 | ping |
Empty | Client -> Server or Peer -> Peer |
| 1 | pong |
Empty | Server -> Client or Peer -> Peer |
| 2 | keyPackageUpload |
openmls-serialised KeyPackage blob (TLS encoding) | Client -> Server |
| 3 | keyPackageFetch |
Target identity key (32 bytes, raw Ed25519 public key) | Client -> Server |
| 4 | keyPackageResponse |
openmls-serialised KeyPackage blob, or empty if none stored | Server -> Client |
| 5 | mlsWelcome |
MLSMessage blob (Welcome variant) |
Peer -> Peer (via DS) |
| 6 | mlsCommit |
MLSMessage blob (PublicMessage / Commit variant) |
Peer -> Group (via DS) |
| 7 | mlsApplication |
MLSMessage blob (PrivateMessage / Application variant) |
Peer -> Group (via DS) |
| 8 | error |
UTF-8 error description string | Any direction |
Control messages (0-1)
ping and pong are keepalive probes with empty payloads. They serve as health checks over long-lived connections.
Authentication messages (2-4)
keyPackageUpload, keyPackageFetch, and keyPackageResponse implement the Authentication Service protocol over the Envelope format. In the current architecture, these operations are handled by the NodeService RPC methods uploadKeyPackage and fetchKeyPackage instead.
MLS messages (5-7)
mlsWelcome, mlsCommit, and mlsApplication carry MLS protocol messages as opaque blobs. The Envelope does not inspect or validate the MLS content; it simply transports the bytes between peers via the Delivery Service.
Error messages (8)
error carries a UTF-8 string describing an error condition. Used for protocol-level error reporting (e.g., "no KeyPackage found for identity").
Relationship to NodeService
The Envelope schema was the original M1 wire format. With the transition to QUIC + TLS 1.3 and Cap'n Proto RPC in M3, the Envelope's role has been superseded by the NodeService interface, which provides typed RPC methods for each operation.
The key differences:
| Aspect | Envelope (M1) | NodeService RPC (M3+) |
|---|---|---|
| Dispatch | Manual, based on msgType enum |
Automatic, Cap'n Proto RPC method dispatch |
| Type safety | Payload is opaque Data |
Each method has typed parameters and return values |
| Transport | QUIC + TLS 1.3 | QUIC + TLS 1.3 |
| Auth | None | Explicit Auth struct per method call |
Further reading
- Wire Format Overview -- serialisation pipeline context
- NodeService Schema -- the current RPC interface that replaced Envelope-based dispatch
- Auth Schema -- standalone Authentication Service interface
- Delivery Schema -- standalone Delivery Service interface
- ADR-002: Cap'n Proto over MessagePack -- why Cap'n Proto was chosen for the wire format