Sealed Envelope Messaging Protocol.
A federated messaging protocol with message-layer encryption, a typed-visibility envelope, DNS-based peer discovery, and an in-protocol identity and key-distribution model. Intended as an SMTP successor for deployments that require end-to-end encryption and metadata minimization at the protocol layer.
Two independent implementations interoperate end-to-end under both baseline (X25519) and post-quantum (Kyber768+X25519) suites, with cross-language test vectors gating every release.
SEMP defines a single wire format and session model covering submission, federation, retrieval, and key distribution. The properties below describe what the protocol itself guarantees, independent of any specific deployment.
Enclosure content is encrypted under per-recipient keys derived at composition time. Servers route and store envelopes without decrypting the enclosure.
Each envelope is a four-layer structure (postmark, seal, brief, enclosure) with explicit visibility per layer. The boundary between server-readable and end-to-end fields is enforced by the construction.
Peer servers locate each other through SRV and TXT records under _semp._tcp.<domain>. Federation handshake reuses the same Noise-style state machine as client sessions.
Each domain publishes signing and encryption keys. User keys are signed by the domain authority. Identity binding is part of the envelope construction itself.
The pq-kyber768-x25519 suite provides hybrid post-quantum key agreement using the same envelope shape and session-key schedule as the classical baseline. Suite negotiation is part of the handshake.
WebSocket (RFC 6455), HTTP/2 (RFC 9113), and QUIC (RFC 9000) bindings are normative. Transport selection is independent of session and envelope semantics.
The SEMP Explorer at explorer.semp.dev drives the semp-ts library through every step of an envelope exchange, federation handshake, client handshake, and discovery round-trip. Each operation appears as a trace step with its actual input and output bytes, a link back to the spec section that defines it, and a paste-into-Node snippet that reproduces the step locally with no SEMP-specific build.
Every cryptographic operation shows its bytes: HKDF outputs, AEAD ciphertexts, KEM ciphertext + shared secret, Ed25519 signatures, MAC tags. The session log isn't a recording; the library runs in the tab and produces the bytes you see.
Flip the suite toggle in the header to rerun the same scenario under the post-quantum hybrid pq-kyber768-x25519. The trace surfaces the byte-length deltas (Kyber768 keys 1184B, ciphertexts 1088B) without changing the envelope shape.
Type another visitor's address into the recipient field to send to a real peer over HTTPS, or leave it empty to wait as the recipient yourself. The trace then renders what arrived, what the server verified, and the bytes the recipient's user-side decrypted.
Every step carries a self-contained Node script that reproduces the operation against the same library version, behind a copy button. No project scaffold, no SEMP-specific build: npm i the listed primitives and the script runs.
Eleven recorded rejection cases run the spec-mandated verification chain on a tampered envelope, attachment, delivery receipt, or first-contact token, and surface where the chain fails and why.
Toggle slow-observation mode and the trace inserts a real pause between operations: a federation handshake takes ten seconds instead of one, every step held long enough to read before the next arrives. Not a UI animation, an actual wait at the wire.
Boundaries the protocol explicitly does not attempt to enforce. Reviewers and implementers should expect these to remain out of scope for v1.0.0.
SEMP raises the cost of abuse through domain-based reputation, proof-of-work, first-contact challenges, and scoped delegation. Determined abuse at scale is a social and economic problem that no protocol can solve alone.
SEMP is designed for incremental adoption. Users may run SEMP and legacy mail accounts in parallel during a transition period; clients present both in a unified inbox with persistent origin indicators. The SEMP server itself stays SEMP-only; legacy interop happens at the client.
Metadata protection is significantly stronger than SMTP. The anonymity guarantees of mix networks or Tor are out of scope for the base protocol. Operators who require stronger anonymity may layer additional infrastructure underneath without protocol-level objection.
No federated messaging protocol can hide the fact that server A contacted server B. SEMP supports multiple key-fetch mechanisms (speculative batch crawling, third-party key relay, direct well-known fetch) with documented privacy and infrastructure tradeoffs; operators choose the order and fallback.
SEMP specifies minimum acceptable algorithms and supports negotiation of stronger suites at handshake time. The two named suites in v1.0.0 are x25519-chacha20-poly1305 and pq-kyber768-x25519; future suites enter through the same negotiation surface without breaking the wire format.
A neutral comparison of architectural and wire-level differences. SEMP and SMTP both target federated person-to-person messaging; the lines below describe where their protocol designs diverge.
seal.signature (domain key, verifiable by any routing server) and seal.session_mac (verifiable by the receiving server). An optional inner signature over the enclosure plaintext binds authorship to the sender's identity key and survives forwarding.K_env_mac)._semp._tcp.<domain> plus a TXT record advertising the protocol version.delivered or rejected) with a machine-readable reason code, signed by the recipient domain. A recipient operating in silent mode for privacy or anti-harassment reasons withholds any wire response; the sender's home server then classifies the timeout as silent for sender-side bookkeeping. Silent acceptance with intent to discard is prohibited.not_found per explicit address. Per-address existence is unobservable; non-existent and policy-rejected addresses receive identical responses in shape, size, and timing (DESIGN.md §2.7).x25519-chacha20-poly1305) and hybrid post-quantum (pq-kyber768-x25519) share envelope and session-key shape.The complete design rationale lives in the spec's extensions.md and the topic-specific drafts. The questions below summarize the most common reviewer entry points.
handshake.md. SMTP runs over TCP without anyone calling it "merely a TCP service."
discovery.md §10.3). No intermediary reads or rewrites messages, so the DKIM-breakage and ARC-workaround problems familiar from SMTP do not arise. For very large groups, an MLS-based extension is sketched in envelope.md §4.4 for logarithmic-cost group key management.
enclosure.forwarded_from of the new envelope. The new recipient verifies the original sender's signature against the original sender's published identity key, giving cryptographic provenance regardless of how many times the message has been forwarded. Automatic forwarding is handled through delegation with a send scope restricted to the forwarding target.
delivered or rejected) with a machine-readable reason code, signed by the recipient domain. A recipient operating in silent mode for privacy or anti-harassment reasons withholds any wire response; the sender's home server classifies the resulting timeout as silent for sender-side bookkeeping. Sender-side queue state (attempt counts, next attempt time, terminal state) is exposed to the submitting client per delivery.md §2. Read receipts (MDN equivalents) are not defined: they compel the recipient device to reveal viewing behavior to a sender with no independent claim on that information, and most privacy-respecting clients strip them today. Vendors who require them MAY define a vendor extension under their own namespace per extensions.md.
delivery.md §1.6). When the acknowledgment is delivered, the recipient server attaches state (available / away / do_not_disturb), an optional freetext message, and an optional until timestamp. The sender learns "recipient is away until July 1" from the acknowledgment the server already generated, with no separate message and no loop risk. Status visibility is opt-in per user, per domain, or per peer. Richer automated responses are a client-layer feature, run as a delegated client with restricted send scope.
SEMP_KEYS request returns signed key records or not_found per explicit address. Per-address existence is unobservable: non-existent and policy-rejected addresses receive responses identical in shape, size, and timing. There is no protocol verb equivalent to VRFY or EXPN, and mailing-list expansion happens on the sender side, so the server never sees list membership.
pq-kyber768-x25519, a hybrid combining ML-KEM-768 (FIPS 203, lattice-based key encapsulation) with X25519 (classical elliptic-curve Diffie-Hellman). If either component is broken the other still protects the session secret. This addresses the harvest-now-decrypt-later threat. Post-quantum protection applies to both the handshake (session key exchange) and the envelope (symmetric key wrapping). Implementations MUST prefer the hybrid suite when both parties support it and MUST NOT downgrade when a stronger suite is available.
discovery.md §8); user-key compromise is bounded by the per-recipient AEAD wrap.
An envelope is a four-layer structure. Each layer has a defined visibility class. Layer boundaries are enforced cryptographically through signatures and AEAD wraps; an honest server cannot read the enclosure, and a misbehaving server cannot forge a brief without detection.
A typical cross-domain delivery sequence. Peer discovery is via DNS SRV. The federation handshake reuses the client handshake state machine; domain keys are fetched on demand via SEMP_KEYS over an established federation session.
[email protected] Server A Server B [email protected] | | | | |-- register (public keys) ->| | | |<- domain keys -------------| | | | | | | |-- handshake -------------->| | | |<- session established -----| | | | | | | |-- encrypted envelope ----->| | | | |-- DNS SRV --------->| | | |<- srv target -------| | | | | | | |-- fetch domain key->| | | |<- domain key -------| | | | | | | |-- federation ------>| | | | handshake | | | |<- session ----------| | | | | | | |-- forward envelope->| | | |<- delivered --------| | |<- delivered ---------------| | | | | |-- fetch ----------->| | | |<- encrypted env ----| | | | | | | | (decrypt locally) |
Two protocol libraries (Go, TypeScript), two reference server implementations, and two reference client implementations are maintained at parity. Each release is gated on the cross-language test vector corpus; the federation harness exercises every server-client combination end-to-end.
Each matrix cell exercises the full session lifecycle: registration, handshake, submission, federation, fetch, decryption, signature verification. Envelopes signed by one implementation decode and verify under the other. The wire format is fixed at v1.0.0 and pinned by the test vector corpus at semp-spec/vectors/v1.0.0.
Each reference repository ships a Go and a TypeScript implementation under impl/go and impl/ts. The two implementations are interchangeable on either side of a session.
git clone https://github.com/semp-dev/semp-reference-server.git cd semp-reference-server/impl/go go build -o semp-server ./cmd/semp-server cp ../../shared/config/config.example.toml semp.toml ./semp-server -config semp.toml
git clone https://github.com/semp-dev/semp-reference-server.git cd semp-reference-server/impl/ts npm install && npm run build node dist/main.js \ --config ../../shared/config/config.example.toml
git clone https://github.com/semp-dev/semp-reference-client.git cd semp-reference-client/impl/go go build -o semp-client ./cmd/semp-client ./semp-client -config alice.toml register -password CHANGEME ./semp-client -config alice.toml send \ -to [email protected] -subject "Hello" -body "First SEMP message" ./semp-client -config bob.toml fetch
git clone https://github.com/semp-dev/semp-reference-client.git cd semp-reference-client/impl/ts npm install && npm run build node dist/cli.js -c alice.toml register -password CHANGEME node dist/cli.js -c alice.toml send \ -to [email protected] -subject "Hello" -body "First SEMP message" node dist/cli.js -c bob.toml fetch
semp.example.com. 3600 IN A 203.0.113.10 _semp._tcp.example.com. 3600 IN SRV 10 1 443 semp.example.com. _semp._tcp.example.com. 3600 IN TXT "v=semp1"
Captured logs from a federation between two independent SEMP servers. Servers located each other through DNS SRV records and exchanged domain signing keys via the federation handshake; no static peer configuration was provided.
$ ./semp-client -config alice.toml send -to [email protected] \ -subject "Cross-domain" -body 'First federated SEMP message!' level=INFO msg=connected server=wss://semp.alpha.com/v1/ws level=INFO msg="session established" session_id=06ERB6WQZMTY7HBDE1GYWATTS4 ttl=5m0s level=INFO msg="envelope sent" [email protected] to=[[email protected]] Envelope submitted: [email protected] [email protected]: delivered
$ ./semp-client -config bob.toml fetch level=INFO msg=connected server=wss://msg.beta.com/v1/ws level=INFO msg="session established" session_id=06ERB71K2FSFG12EVJ2XCSXK08 ttl=5m0s level=INFO msg="fetched envelopes" count=1 drained=true --- Message [email protected] --- From: [email protected] To: [email protected] Subject: Cross-domain Body: First federated SEMP message! 1 message(s) fetched.
Two suites are normative in v1.0.0. Both share the same envelope structure, signature framework, and five-key session schedule. The suite is selected at handshake time and recorded in the postmark.
Specification under Creative Commons Attribution 4.0. Implementations under MIT.
Normative specification. Eight Internet-Draft topics covering architecture, envelope, handshake, discovery, delivery, recovery, extensions, and client. Includes the cross-language test vector corpus under vectors/v1.0.0/.
Protocol library in Go. Covers crypto suites, handshake state machines, envelope composition and parsing, delivery pipeline, transport bindings, federation, and discovery.
Protocol library in TypeScript. Conforms to the same test vector corpus as semp-go.
Reference server. Each implementation provides client and federation WebSocket endpoints, registration API, well-known discovery, SQLite storage, and DNS SRV federation. The two implementations are interoperable on every endpoint.
Reference client. CLI only. Covers key registration, handshake, submission, fetch, decryption, key requests, session rekeying, and the .semp file import/export format.
SEMP is in a phased rollout: anchor the wire format, submit at IETF, gather external review, expand language coverage. The current phase is documented below for prospective implementers and reviewers.
Cross-language test vector corpus locked. Two protocol libraries pass the corpus byte-for-byte. Polyglot reference server and client repositories pass the cross-implementation federation matrix.
CompleteSEMP is structured as an eight-draft series for submission to the IETF.
In progressOutreach to the IRTF CFRG mailing list and to academic cryptography groups. Substantive feedback is absorbed into the specification before further implementations propagate from the v1.0.0 wire format.
In progressLibrary ports beyond Go and TypeScript, in declared priority order: Rust, Python, Swift, Kotlin. Each port is required to pass the cross-language test vector corpus and join the federation matrix before being declared conformant.
PlannedCoverage extension into error paths, federation edge cases, and fuzzing-derived corner cases. New vectors that surface specification ambiguity feed the next draft revision.
Ongoing