@me2em/crypto
    Preparing search index...

    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 or destroyChannel.

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

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

    Channel objects are FROZEN (D2): all fields are readonly and the object is sealed with Object.freeze at creation — mutation attempts throw in strict mode. Functions accepting a Channel validate the runtime brand (D1) and reject impostor objects with INVALID_ARGUMENT.

    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";
    }
    Index
    channelId: string

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

    epoch: number

    0 after establish; grows on rotate.

    role: "initiator" | "recipient"

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