xsp-auth
The XSP-AUTH mutual proof-of-control handshake calculus — SIGMA-style signed ephemeral X25519 over four messages riding ordinary XSP v1 frames on stream 0, with the per-request possession proof and the rotation-continuity proof beside it. Every verb is pure: nonces and ephemeral keypairs are generated by the impure caller and injected, so the whole calculus is offline and deterministic.
xsp-auth:hello
[$xsp-auth:hello] -> element — Build the XSP-AUTH M1 hello from injected randomness (nonce, ephemeral X25519 public key), the dialed endpoint, and an optional initiator DID (absent = anonymous).
xsp-auth:challenge
[$xsp-auth:challenge] -> element — Responder side: validate M1 and build M2, signing the role-pinned transcript with the responder's Ed25519 seed — there is no anonymous responder.
xsp-auth:prove
[$xsp-auth:prove] -> element — Initiator side: verify M2 (selected version, channel-binding equality, responder transcript signature), derive the key schedule, and build M3 with the key-confirmation tag, the attach request, and — when a DID is claimed — the initiator transcript signature.
xsp-auth:confirm
[$xsp-auth:confirm] -> element — Responder side: verify M3 (initiator tag; transcript signature when a DID is claimed; anonymous refused under require-mutual), then build M4 carrying the responder key-confirmation tag and the attach result session.
xsp-auth:finish
[$xsp-auth:finish] -> element — Initiator side: verify M4's responder key-confirmation tag and return the [xsp-auth-established …] report with the responder DID, channel id, and bound session.
xsp-auth:transcript
[$xsp-auth:transcript] -> element — Assemble the signed transcript element — M1 verbatim plus M2 with its [sig] child stripped — the exact subject of both handshake signatures.
xsp-auth:keys
[$xsp-auth:keys] -> element — Derive the HKDF key schedule (confirmation tags, per-direction proof keys, channel id) from the ephemeral X25519 shared secret salted by both nonces; both sides derive identical values.
xsp-auth:verify
[$xsp-auth:verify] -> bool — Low-level transcript-signature check for one role; the initiator role additionally covers the responder's signature (transcript closure).
xsp-auth:rotate
[$xsp-auth:rotate] -> element — Produce a §6.3 rotation continuity proof: the outgoing key signs the incoming DID bound to the prior channel id, attesting the new key's holder held the old.
xsp-auth:rotate-verify
[$xsp-auth:rotate-verify] -> bool — Verify a rotation continuity proof against the outgoing key (offline-recovered from a did:key/did:peer old DID, or supplied for did:web).
xsp-auth:frame-check
[$xsp-auth:frame-check] -> string — Enforce the §4.8 post-handshake binding: an empty-principal frame inherits the session principal; a non-empty principal must equal it or the frame is rejected — the rule that makes the XSP principal field a checked label, never an identity source.
xsp-auth:proof
[$xsp-auth:proof] -> bytes — Compute the per-request possession proof for request/response transports: HMAC(key, counter-be8 concatenated with sha256(frame-bytes)).
xsp-auth:proof-verify
[$xsp-auth:proof-verify] -> bool — Verify a per-request possession proof in constant time; a counter below 1 never verifies.