Koder Pair — peer-to-peer device pairing handshake

mandatory

Protocolo de handshake para pareamento peer-to-peer entre dispositivos do mesmo dono na Koder Stack (Kode CLI, Kanvas, Talk, Drive, etc.). Define discovery via mDNS/bluetooth, key exchange (Noise XX), confirmação visual cross-device e armazenamento da relação no Koder Keys.

Spec — Koder Pair: peertopeer device pairing handshake

*tatus:*Normative (Draft) *pplies to:*engines/sdk/koder_pair_kit/, products/horizontal/pair/, any Koder app that wires same-owner device pairing (Kode CLI, Kanvas, future). *rigin:*KSTACK34 (OpenClaw analysis 202604-29). *rypto reuse:*Noise Protocol Framework — same primitives as products/horizontal/talk (RFC-001 QUIC transport). Do NOT introduce new cryptographic primitives.


1. Scope

This spec defines the *andshake*that establishes a Koder Pair session between two devices owned by the same human (e.g. desktop ↔ phone). Once established, the session reuses the Talk transport (Noise-encrypted streams over QUIC).

*ut of scope:*application-level message formats (Pair owns one per app: audio relay, notification mirror, co-pilot). Each consumer defines its own protobuf on top of the Pair session.

2. Pairing Modes

Two modes, both producing the same end state:

2.1 QR + Outofband

Default for casual setups (phone ↔ laptop in the same room).

  1. Initiator (e.g. desktop) calls pair.PrepareInvite() → returns:
    • pair_token: 256-bit random, expires in 5 minutes
    • initiator_pubkey: Ed25519 public key
    • endpoint: host:port reachable on LAN, plus optional

      relay_url for crossnetwork pairing via Koder Hubhosted relay (see §5)

  2. Initiator displays a QR encoding pair://{token}@{endpoint}?pk={pk_b64}.
  3. Responder scans the QR with the Pair app, calls pair.JoinInvite(uri).
  4. Responder generates its Ed25519 keypair, opens a Noise XX handshake

    over QUIC to endpoint, presents pair_token in the handshake prologue.

  5. Initiator verifies token, completes Noise XX, returns its long-term

    identity in the final handshake message.

  6. Both sides write the peer's identity to local keystore — future

    sessions skip the QR step (use Noise IK directly).

2.2 PIN fallback

When the QR camera is unusable (server pairing, wearable, accessibility):

  1. Initiator calls pair.PreparePIN() → returns:
    • 6-digit human PIN (displayed)
    • pair_token (same as 2.1)
  2. Responder enters PIN manually; SDK derives pair_token from PIN +

    shared discovery channel context (so PINs alone don't authorize — the discovery channel proximity is part of the proof).

PIN mode requires both devices on the same LAN OR both authenticated to the same Koder ID v2 account (the relay validates both auth tokens).

3. Cryptographic Choices

Property Value
Identity keys Ed25519 (matches Talk)
Handshake Noise XX (mutual auth, forward secrecy)
Session keys Derived via Noise XX → ChaCha20-Poly1305
Transport QUIC (matches Talk RFC-001)
Identity persistence Per-device keystore via OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows, KeyStore on Android, Keychain on iOS)

Reuses every primitive from `productshorizontaltalk/RFC001` — no new crypto reviewed. New auditing surface is limited to the prologue (token+PIN handling).

4. Session Lifetime

  • Each Pair session is *erdevicepair* not per-app. Multiple Koder

    apps share the same underlying Noise session via the Pair daemon.

  • Session is *ersistent*across restarts (re-handshake on first

    message after reboot using cached identities — Noise IK pattern).

  • *evocation:*the user can revoke a paired peer in any Koder app's

    Settings → Paired Devices. Revocation broadcasts a tombstone via the Hub-hosted relay (see §5) so all this user's devices update their trust list.

5. Relay (cross-network pairing)

When devices aren't on the same LAN, the Hub hosts a thin relay at pair.koder.dev/relay:

  • Initiator and Responder both authenticate to the relay with their

    Koder ID v2 token (so the relay can confirm same-owner).

  • Relay forwards Noise frames byteforbyte; *ever decrypts*

    (it has no key material).

  • Relay is rate-limited per Koder ID account (10 active sessions, 100

    pairings/day).

6. Validation

  • Smoke test: pair desktop+phone via QR; verify kode device list

    shows both; revoke from desktop; verify phone no longer in the list.

  • Property test: handshake with corrupted pair_token MUST fail before

    any session key derivation.

  • Audit: cryptographic review limited to §2 prologue handling — Noise

    primitives below are inherited from Talk and don't need re-audit.

7. Non-Goals

  • Multiuser mesh. Pair is for *ameowner*device sets only. Talk

    handles multi-user.

  • File transfer protocol. Pair sessions carry app-specific protobuf

    streams; large transfers ride on top via app-level chunking.

8. References

  • products/horizontal/talk/docs/rfcs/RFC-001-quic-transport.md — Noise + QUIC stack inherited
  • services/foundation/id — Koder ID v2 auth used by §5 relay
  • engines/sdk/koder_pair_kit/docs/rfcs/RFC-001-pair-architecture.md — implementation spec

Source: ../home/koder/dev/koder/meta/docs/stack/specs/pair/handshake.kmd