Media, calls and end-to-end encryption
This appendix describes the programs and libraries that give RCE programs media, calls and end-to-end encryption (E2EE): encryption in which only the communicating peers hold the keys, so relays and storage see ciphertext only. Everything here is ordinary RCE code run on the host contract of Appendix E of the RCE specification. Nothing in it adds a primitive to that contract or changes the meaning of any program. The rules it relies on are HC-3 (one result event per output request), HC-7a (fuel per input), HC-8 (replay with adapters disconnected) and HC-10 (every input is an event in the log D).
Principles
- Randomness is an input. No library here draws random bytes. Every
private key, ephemeral key and seed comes from a logged
Randomresult (HC-10), so a session replays bit for bit and a test can fix every byte. - One public-key operation per input. A step that runs X25519 (the
Diffie-Hellman function on Curve25519 of RFC 7748, a Request for
Comments of the Internet Engineering Task Force) or a post-quantum key
encapsulation does one such operation per input, so each input stays
within the fuel of 6.7 that HC-7a grants it. Programs queue the work
and run one job per
Pollinput. - Not constant time. The libraries are reference code for correctness and replay. Their running time depends on secret data, so a host that faces timing attackers runs them where timing is not observable or uses a vetted adapter through 5.11.
- Secrets stay in D, and D stays on the device. Private keys and
ratchet state are program state, and the
Randomresults that made them are entries of D. D is device-local;rce host replay --redact(chapter 16) shows such fields as digests. - Checked against official vectors. Each library carries
checklines for its primitives (run withrce test lib/FILE.rce), and the test suite runs the official vectors of each standard as host steps and then replays the log.
Media and the selective forwarding unit (SFU)
The media adapters (chapter 16, enabled with --media DIR) turn capture and
playback into events: D holds (track, sequence number, digest) per frame
and the frame bytes are blobs addressed by their Secure Hash Algorithm
256 (SHA-256) digest. A call between more than two peers needs a relay
so that each publisher sends a frame once. apps/sfu.rce is that relay,
a selective forwarding unit (SFU), written in RCE.
Peers reach the SFU over remote channels. Each wire body is fields separated by U+001F:
| Body | Meaning |
|---|---|
sub ROOM TRACK | subscribe the sender to a track of a room |
unsub ROOM TRACK | drop that subscription |
frame ROOM TRACK SEQ DIGEST PAYLOAD | a frame from its publisher; SEQ orders it, DIGEST names its blob, PAYLOAD is opaque |
The SFU forwards a frame, naming its publisher, to every other
subscriber of the track, as an unreliable send: never retried, so a lost
frame is one ChanSendDone result that is not delivered (HC-3). A
frame whose SEQ is not newer than the last one forwarded for that
(room, track, publisher) is dropped as stale, so the latest frame wins.
A SEQ that is not 1 to 18 decimal digits, or a body of another shape, is
counted as malformed: a peer cannot make the SFU refuse an input. The
SFU folds only (track, sequence number, digest) into its state, never a
payload, and payloads are end-to-end ciphertext it cannot read. A runnable example is run.sh sfu in the examples of the host runtime.
Direct messages: X3DH and the Double Ratchet
lib/crypto.rce provides SHA-256, the keyed hash HMAC (Hash-based
Message Authentication Code), HKDF (the HMAC-based Key Derivation
Function of RFC 5869), X25519, the Ed25519 signature scheme (RFC 8032)
and an authenticated encryption with associated data (AEAD) built from
the ChaCha20 stream cipher with an HMAC-SHA-256 tag. The chat program of chapter 16 uses them for direct messages. Each
replica has an X25519 identity key, an Ed25519 signing key and an X25519
signed prekey. It publishes a bundle of the public keys with an Ed25519
signature over the prekey; a received bundle is used only when its
signature verifies. For each pair of peers, the one whose name sorts
first runs X3DH (the Extended Triple Diffie-Hellman key agreement) as
initiator, and both sides then keep one Double Ratchet per peer, so
every message has its own key. A message whose plaintext is not
well-formed UTF-8 is dropped and counted.
Post-quantum key agreement: ML-KEM-768 and PQXDH
lib/pq.rce adds post-quantum key agreement, used together with
lib/crypto.rce:
- Keccak and its functions SHA3-256, SHA3-512, SHAKE128 and SHAKE256 of the Federal Information Processing Standard (FIPS) 202.
- ML-KEM-768, the Module-Lattice-based Key Encapsulation Mechanism (KEM)
of FIPS 203 at its middle security level:
mlkem_keygen(d, z)gives an encapsulation key and a decapsulation key,mlkem_encaps(ek, m)a ciphertext and a shared secret,mlkem_decaps(dk, c)the shared secret. A forged ciphertext yields an unrelated secret (implicit rejection) rather than an error. - PQXDH, Signal's post-quantum extension of X3DH. The responder
publishes an identity key, a signed prekey and an ML-KEM prekey signed
with its Ed25519 identity. The initiator runs three X25519 exchanges
(
pqxdh_dh_init) and encapsulates to the ML-KEM prekey; the responder runs the same exchanges from its side (pqxdh_dh_resp) and decapsulates. Both derive the session key SK = HKDF(F ‖ DH1 ‖ DH2 ‖ DH3 ‖ SS) withpqxdh_sk, where F is 32 bytes of 0xFF and SS the KEM shared secret. An attacker must break both X25519 and ML-KEM to learn SK.
Each of these is several inputs, one operation each (see Principles). A runnable example is run.sh pqxdh in the examples of the host runtime, which checks the ML-KEM
shared secret against the RustCrypto ml-kem crate, that both sides
derive the same SK, and that the log replays with secrets redacted.
HPKE and AES-128-GCM
lib/hpke.rce provides AES-128-GCM, the Advanced Encryption Standard of
FIPS 197 with a 128-bit key in Galois/Counter Mode (GCM) of the National
Institute of Standards and Technology (NIST) Special Publication
800-38D, an AEAD. On top of it is HPKE, Hybrid Public Key Encryption of
RFC 9180, in base mode with the suite DHKEM(X25519, HKDF-SHA256),
HKDF-SHA256 and AES-128-GCM:
hp_derive_sk(ikm)derives a private key from input keying material (DeriveKeyPair).hpke_seal(pkr, ske, info, aad, pt, seq)encrypts to the recipient's public key with the ephemeral private keyske(from logged random bytes) and givesenc.ciphertextin hexadecimal;seqis the message number of the context.hpke_open(skr, enc, info, aad, ct, seq)gives the plaintext, or the empty text when the ciphertext, the additional authenticated data (AAD) or the key does not match.encrypt_with_labelanddecrypt_with_labelare the EncryptWithLabel and DecryptWithLabel operations of MLS (below).
The test suite checks the RFC 9180 base-mode vector at sequence numbers
0, 1, 2, 255 and 256 and the MLS EncryptWithLabel vector. A runnable example is run.sh hpke in the examples of the host runtime.
Group keys: MLS
lib/mls.rce is the first part of Messaging Layer Security (MLS), the
group key agreement of RFC 9420, for cipher suite 1
(MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519). It provides:
- The ratchet tree math of Appendix C of RFC 9420: the nodes of a tree
of n leaves are 0 to 2n-2 with leaves at even indices, and
tm_root,tm_parent,tm_sibling,tm_direct_pathandtm_copathgive the structure. - The key schedule of section 8:
mls_epoch(init, commit, psk, ctx)takes the previous epoch's init secret, this commit's commit secret, the pre-shared key (PSK) secret and the serialized GroupContext, and gives the joiner, welcome and epoch secrets, every secret derived from the epoch and the next init secret. mls_export, the MLS exporter, andmls_external_pub, the external HPKE public key of an epoch.
The test suite checks the official tree-math.json and
key-schedule.json vectors (all five epochs of suite 1). TreeKEM path
secrets, commits, adds and removes are later parts. A runnable example is run.sh mls in the examples of the host runtime, whose examples hold the epoch 0
vector.
The sandbox under these programs
The sandbox of HC-5 is one contract, independent of any operating system
(OS): the checker admits only programs whose effects go through granted
capabilities, and the host refuses any effect without one before any OS
layer is involved. The media, channel and storage adapters above are
reached only through such capabilities. The same contract has
enforcement targets underneath the host: WebAssembly (WASM), bare metal,
Linux, macOS, Windows and other OSes, each entered as strictly as the
target allows (HC-5 lists the mechanisms). rce host prints the target
it entered at start. The contract conforms to OpenIE Sandbox v0.1
(https://sandbox.transaction.science) and to the Joule Context Protocol
(JCP) v0.3 (https://jcp.transaction.science).