Skip to content

docs: Add audio call feasibility plan#2

Merged
etnt merged 2 commits into
mainfrom
copilot/add-audio-call-support
May 5, 2026
Merged

docs: Add audio call feasibility plan#2
etnt merged 2 commits into
mainfrom
copilot/add-audio-call-support

Conversation

Copilot AI commented May 4, 2026

Copy link
Copy Markdown
Contributor

Feasibility study for adding E2E encrypted audio calls between Cryptic users, covering transport architecture, encryption model, signaling protocol, and phased implementation path.

Key decisions

  • Transport: P2P via ICE + DTLS-SRTP (UDP) as primary path; server-relayed encrypted frames as automatic fallback — no full WebRTC stack dependency
  • Encryption: DTLS fingerprints exchanged inside the existing Double Ratchet channel; audio encrypted with SRTP derived from the DTLS handshake — keeps high-throughput SRTP separate from the per-message ratchet
  • Signaling: New JSON message types (call_invite, call_answer, call_ice_candidate, call_hangup) over the existing WebSocket mTLS channel; server routes by looking up peer PID in user_connections ETS
  • Clients: Audio I/O scoped to the Rust TUI (cpal + opus + webrtc-rs); Erlang console limited to signaling commands in v1
  • NAT traversal: ICE + self-hosted coturn TURN server

Phased delivery

  1. Signaling infrastructure + UI commands (no audio)
  2. Server-relayed audio PoC (Rust TUI end-to-end)
  3. P2P via ICE/DTLS-SRTP + TURN fallback
  4. Hardening (jitter buffer, frame padding, rate limiting, call metadata storage)

Out of scope

Group calls (requires SFU), video, call recording.

@etnt

etnt commented May 4, 2026

Copy link
Copy Markdown
Owner

What about cryptic-mobile?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new feasibility/planning document describing how Cryptic could implement E2E-encrypted 1:1 audio calls, leveraging existing WebSocket/mTLS signaling and Double Ratchet for DTLS fingerprint authentication.

Changes:

  • Introduces a detailed architecture plan covering transport (ICE + DTLS-SRTP + relay fallback), encryption binding, signaling message types, and phased delivery.
  • Proposes server-side routing via existing user_connections ETS lookups and outlines optional relay/registry modules.
  • Scopes initial audio support to the Rust TUI, with console client limited to signaling commands in v1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/AUDIO_CALL_FEASIBILITY_PLAN.md Outdated
Comment on lines +230 to +233
the existing Double Ratchet session derives a 32-byte "call binding key"
`K_call` using a dedicated context string (e.g.,
`KDF(chain_key, "audio_call_v1")`). This is communicated as part of the
encrypted SDP offer message, not transmitted in plaintext.
Comment thread docs/AUDIO_CALL_FEASIBILITY_PLAN.md Outdated
authenticated identity.

3. **SRTP via DTLS-SRTP** (RFC 5764): DTLS establishes the master key for SRTP.
Audio frames are encrypted with SRTP (AES-128-GCM or ChaCha20 profiles).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are only considering communication between Cryptic clients, hence ChaCha20 should be fine, or?

Comment on lines +332 to +342
#### `call_reject`
Bob declines.
```json
{
"type": "call_reject",
"call_id": "uuid-1234",
"from_user": "bob",
"to_user": "alice",
"reason": "busy"
}
```
Comment on lines +355 to +367
### Server Relay Message Types (when P2P fails)

#### `call_relay_frame`
An encrypted Opus audio frame relayed through the server.
```json
{
"type": "call_relay_frame",
"call_id": "uuid-1234",
"from_user": "alice",
"to_user": "bob",
"seq": 42,
"encrypted_frame": "base64..."
}
Comment thread docs/AUDIO_CALL_FEASIBILITY_PLAN.md Outdated
CallType =:= <<"call_hangup">> ->
ToUser = maps:get(<<"to_user">>, Msg),
relay_to_user(ToUser, Msg),
{ok, State};
- Fix K_call derivation inconsistency: clarify that both sides derive
  K_call locally from chain_key + call_nonce via HKDF (not communicated)
- Clarify SRTP profiles: AEAD_AES_128_GCM (RFC 7714) as mandatory;
  ChaCha20-Poly1305 noted as non-standard Cryptic-specific extension
- Fix Cowboy callback return type: {[], State} instead of {ok, State}
- Add context for call_reject (additional signaling message) and
  call_relay_frame (relay-mode only, Phase 2+)
@etnt etnt marked this pull request as ready for review May 5, 2026 07:19
@etnt etnt merged commit 4e9ef81 into main May 5, 2026
1 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants