Skip to main content
HUMΛN
Passport
Passport

Multi-device E2E sync: ECDH, QR pairing, and the honest path from relay to P2P

HUMΛN Team··12 min·Client + Security engineers

Pairing “succeeds” in logs. Decrypt fails in the app. Two clients used different HKDF info labels. That failure class destroys trust faster than a loud auth error—because the user thinks they are synced when they are not.

Multi-device Passport sync is ECDH handshake, QR ceremony, and an honest staging story from relay to P2P—not a slide that says “E2E” while ciphertext still parks in our DB by default.

Crypto suite choice

ECDH P-256 + HKDF-SHA256 + AES-256-GCM aligns with WebCrypto across browsers and Workers. X25519 + ChaCha20-Poly1305 can be preferable in some native stacks—Phase 6 prioritized portability and a shared review surface.

HKDF info / salt labels must match byte-for-byte across clients. Copy-paste bugs here produce the worst class of failure: silent decrypt mismatch after a happy QR scan.

Three-step flow (conceptual)

  1. sync/initiate — mint QR nonce; short TTL (~60s) to limit blast radius.
  2. sync/approve — primary device signs attestation; server verifies JWS (ES256 family consistent with passport keys).
  3. sync/complete — enroll long-lived device signing key; rotate session material.

QR payload: include v for versioning, session_id, did, qr_nonce, ephemeral pubkey, expires_at. JSON → base64url for the QR string (CBOR deferred if size constraints bite).

Audit-only field

sync_encryption_key_hash = SHA-256 of ephemeral ECDH public material for audit correlation only. Never feed this hash into decrypt paths—doing so turns an audit artifact into a footgun for the next engineer.

Relay vs P2P (honest staging)

Vault ciphertext may traverse a DB-backed relay in some flows while P2P ships. Canon expects true P2P for identity payloads long-term; @canon-deviation documents relay until WebRTC/DataChannel is default for capable clients. Signal-only design: Sync without us in the middle.

Tests (minimum)

  • Nonce uniqueness and replay rejection
  • Stale/expired session → 400 with structured problem details
  • Partial DB indexes for pending session sweeps (ops hygiene)
  • Cross-client HKDF vector parity (fixture shared across TS/Rust if applicable)

Scroll-stopper: Happy pairing logs with failed decrypt is worse than a refused QR—the user believes they are protected when they are not.

So that…

…client teams share one crypto vector set; auditors know sync_encryption_key_hash is correlation-only; and relay is named as staging toward P2P—not sold as the final architecture.

Go deeper

— Part of