Skip to main content
The Signal struct provides direct access to Signal protocol operations including message encryption/decryption for both 1:1 and group conversations, session management, and participant node creation.
These are low-level APIs that bypass the high-level message sending pipeline. Most users should use client.send_message() which handles encryption automatically. Use these methods only when you need direct control over the Signal protocol layer.

Access

Access Signal protocol operations through the client:

Methods

encrypt_message

Encrypt plaintext for a single recipient using the Signal protocol.
Parameters:
  • jid - Recipient JID. PN JIDs are resolved to LID and Hosted JIDs to HostedLid when a mapping exists, matching WA Web’s SignalAddress.toString() and the internal send path. See Signal address resolution.
  • plaintext - Raw bytes to encrypt. The caller is responsible for padding if needed.
Returns:
  • (EncType, Vec<u8>) - The encryption type and ciphertext bytes
EncType variants:
  • EncType::PreKeyMessage - Session was just established (includes prekey bundle)
  • EncType::Message - Standard encrypted message
Example:

decrypt_message

Decrypt a Signal protocol message from a sender.
Parameters:
  • jid - Sender JID. PN JIDs are resolved to LID and Hosted JIDs to HostedLid when a mapping exists.
  • enc_type - The encryption type (EncType::PreKeyMessage or EncType::Message)
  • ciphertext - Encrypted bytes to decrypt
Returns:
  • Vec<u8> - Raw padded plaintext. Use MessageUtils::unpad_message_ref with the stanza’s v attribute if WhatsApp message unpadding is needed.
Passing EncType::SenderKey returns an error — use decrypt_group_message for sender-key encrypted group messages.
Example:

encrypt_group_message

Encrypt plaintext for a group using sender keys.
Parameters:
  • group_jid - Group JID (@g.us)
  • plaintext - Raw bytes to encrypt
Returns:
  • (Option<Vec<u8>>, Vec<u8>) - A tuple of optional SKDM bytes and ciphertext bytes. The SKDM is Some only when a new sender key was created (first encrypt for this group or after key rotation). You must distribute the SKDM to all group participants when present.
Not safe to call concurrently with decrypt_group_message for the same group — sender key state is not internally locked.
Example:

decrypt_group_message

Decrypt a group (sender-key) message.
Parameters:
  • group_jid - Group JID
  • sender_jid - Sender’s JID within the group
  • ciphertext - Encrypted bytes to decrypt
Returns:
  • Vec<u8> - Raw padded plaintext. Use MessageUtils::unpad_message_ref with the stanza’s v attribute if WhatsApp message unpadding is needed.
Not safe to call concurrently with encrypt_group_message for the same group — sender key state is not internally locked.
Example:

validate_session

Check whether a Signal session exists for a JID.
Parameters:
  • jid - JID to check. PN JIDs are resolved to LID and Hosted JIDs to HostedLid when a mapping exists.
Returns:
  • bool - true if a session exists, false otherwise
Example:

delete_sessions

Delete Signal sessions and identity keys for the given JIDs.
Parameters:
  • jids - JIDs whose sessions and identity keys should be deleted. PN JIDs are resolved to LID and Hosted JIDs to HostedLid when a mapping exists.
This matches WhatsApp Web’s deleteRemoteSession behavior, which removes both the session and identity key as a paired operation. Changes are flushed to the persistent backend before returning. Example:

create_participant_nodes

Create encrypted participant <to> nodes for the given recipient JIDs.
Parameters:
  • recipient_jids - JIDs to encrypt for
  • message - Protobuf message to encrypt
Returns:
  • (Vec<Node>, bool) - The encrypted participant XML nodes and a boolean indicating whether a device identity node should be included in the stanza (true when any participant received a PreKey message).
This method resolves devices, ensures Signal sessions exist, encrypts the message for each device, and returns the resulting XML nodes. It acquires session locks matching the DM send path via session_mutexes_for() (bare recipient JID for the recipient, per-device for own companion devices). Example:

assert_sessions

Ensure E2E sessions exist for the given JIDs.
Parameters:
  • jids - JIDs to ensure sessions for
If sessions do not exist, this method fetches prekey bundles from the server and establishes new sessions. Example:

get_user_devices

Get all known device JIDs for the given user JIDs via usync.
Parameters:
  • jids - User JIDs to query
Returns:
  • Vec<Jid> - All device JIDs for the given users
Example:

EncType

The EncType enum represents the Signal protocol encryption type used for a message:
EncType exposes two predicate helpers: is_session() (true for Message / PreKeyMessage, excludes MessageSecret) and is_bot_secret() (true only for MessageSecret).

Bot message decryption (msmsg)

When you message Meta AI or another @bot account, the bot’s replies arrive as <enc type="msmsg"> stanzas. These are not Signal-session encrypted — they use a dual-HKDF derivation over the 32-byte messageSecret from the prompt you sent, then AES-256-GCM. The client handles this end to end and transparently:
  1. On send to a bot, the outbound MessageContextInfo.messageSecret is persisted (keyed by (chat, sender, msg_id)) so the reply can be decrypted later.
  2. On receive, an msmsg stanza is decrypted and decoded into a wa::Message, then dispatched as a normal Event::Messages — there is no separate bot event. The sender is the bot JID (e.g. …@bot) and MsgMetaInfo.target_id points back at your original prompt.
  3. On failure (missing secret, GCM tag mismatch, malformed proto) the client nacks with reason 495 (MissingMessageSecret) instead of silently dropping, and group bot replies are acked with a bare <ack class="message"> matching WA Web.
You don’t need to call anything — receiving bot replies works as soon as you’ve sent a message to the bot from the same client. The low-level primitive is wacore::bot_message::decrypt_bot_message(message_secret, enc_iv, enc_payload, ctx), and persistence is backed by the MsgSecretStore trait.

Usage examples

Manual 1:1 encryption round-trip

Check session before sending

Group encryption with SKDM handling

Reset a broken session

Error types

SignalError

All signal methods return Result<T, SignalError>:
Variants:
  • Protocol — Signal protocol error (session mismatch, decode failure, etc.)
  • Unsupported — Operation not supported for the given parameters
  • Internal — Catch-all for other errors

See also