← Blog
0.7.0 · OS · SRDX · SECURE · MILESTONE

SRDX Secure Invite — Ed25519-Signed One-Use Session Invite (sigil-os 2baf970)

os srdx security crypto milestone 0.7.0

cc0/net/srdx_invite.sg closes the SRDX secure session onboarding gate: a 128-byte wire blob carries host_pubkey + ext_ip + port + session_token + expires_unix + Ed25519 signature over the first 64 bytes. The invite is a capability: the holder can join the session exactly once, within the TTL window. Base64url encode/decode hardcoded for the fixed 128B → 171-char wire form. Host tracks used tokens for replay-rejection. 5 QEMU tests PASS (gen/parse round-trip, expiry, mark/is_used).


Invite blob and security model

128B wire blob: structure and Ed25519 signature

blob layout (128B)
Fixed-field layout: bytes 0–31 = host_pubkey (Ed25519 public key, 32B); bytes 32–35 = ext_ip (IPv4 in network byte order, 4B); bytes 36–37 = port (big-endian, 2B); bytes 38–53 = session_token (16B random token identifying this session); bytes 54–57 = expires_unix (4B Unix timestamp of expiry); bytes 58–63 = padding/reserved; bytes 64–127 = ed25519_sig (64B Ed25519 signature over bytes 0–63). The signature covers the entire header — host identity, address, token, expiry — but not itself: a standard detached signature construction.
srdx_invite_gen()
Takes host_privkey, host_pubkey, ext_ip, port, session_token, expires_unix. Fills bytes 0–63 with the structured header fields, then computes the Ed25519 signature over those 64 bytes using host_privkey and writes the 64-byte result into bytes 64–127. Returns the complete 128B invite blob.
srdx_invite_base64url_encode(blob)
Encodes the 128B blob to the 171-char base64url wire form. Hardcoded for 128B input — no general-purpose encoder needed. The 171-char string is the shareable invite: a link, a QR code, or a paste. Decodes back to exactly 128B via srdx_invite_parse.

Validation, expiry, and replay-rejection

srdx_invite_parse(encoded)
Decodes the 171-char base64url string back to the 128B blob; extracts all fields (host_pubkey, ext_ip, port, session_token, expires_unix, ed25519_sig) into caller-supplied output slots. Inverse of srdx_invite_base64url_encode; round-trips cleanly (QEMU T1 PASS).
srdx_invite_verify(blob, now_unix)
Three-step validation: (1) verifies the Ed25519 signature over bytes 0–63 using host_pubkey embedded in the blob itself — the signer is self-identified, no out-of-band key lookup needed; (2) checks expires_unix > now_unix — TTL not expired (QEMU T2 PASS: expired invite returns EXPIRED); (3) checks the session_token has not been seen before via srdx_invite_is_used — replay-rejection. Returns one of: VALID, EXPIRED, BAD_SIG, or REPLAYED.
srdx_invite_mark_used(host, session_token)
Records the 16B session_token in the host's used-token table after a VALID invite is accepted. Called once, immediately before admitting the joining peer. The used-token table is an in-memory set bounded by the number of concurrent sessions — compact and exact. (QEMU T4 PASS: mark then is_used returns true.)
srdx_invite_is_used(host, session_token)
Looks up whether a token has been seen before. Returns true if the token is in the used-token table. A token can only be accepted once per host lifetime — a replayed invite fails at step (3) of srdx_invite_verify with REPLAYED regardless of signature validity or TTL. (QEMU T5 PASS: replayed token returns REPLAYED.) The invite is modelled as a capability: a short-lived, unforgeable, single-use grant to join a specific SRDX session at a specific host address, proven by the host's long-term Ed25519 identity key.