Interface Channel

A long-lived E2EE channel derived from an X3DH shared secret.

Key representations coexist: the raw root material (32B) lives in module-private internals (WeakMap) for message-key derivation and rotation; a non-extractable CryptoKey is derived from it for AEAD operations. The raw material is wiped only at rotation.

Sequence counters are managed by the APPLICATION (immutable design — React-friendly).

The channel's internal state (rootKeyMaterial, lastDecryptedSeq) is stored in a module-private WeakMap keyed by the Channel object reference. The application never sees or touches internals.

const x3dh = await initiateX3DH(myIdentity, theirBundle);
const channel = await establishChannel(
x3dh.sharedSecret, 'chat-42');
const msg = await encryptChannelMessage(channel, 0, plaintext);
interface Channel {
    channelId: string;
    epoch: number;
    role: "initiator" | "recipient";
}

Properties

Properties

channelId: string

hex(SHA-256(sharedSecret ‖ salt)) — identical on both sides.

epoch: number
role: "initiator" | "recipient"

Direction role: affects nothing cryptographically (X3DH is symmetric), but useful for application-side audit. Set on establish, preserved through rotation.