BaileysEx.Native.Noise (baileys_ex v0.1.0-alpha.8)

Copy Markdown View Source

Low-level raw Noise XX NIF wrapping the snow crate.

This is not the WhatsApp protocol surface. Baileys' real handshake flow is protobuf-wrapped and certificate-aware, so the reference-aligned implementation lives in BaileysEx.Protocol.Noise.

Keep this wrapper sharp and limited: it exposes the underlying raw XX state machine for low-level tests and experiments, while the WhatsApp-specific choreography stays at the protocol layer.

The session lifecycle is:

  1. init/1 -- create an initiator handshake session with a prologue
  2. handshake_write/2 / handshake_read/2 -- exchange XX pattern messages
  3. finish/1 -- transition to transport mode
  4. encrypt/2 / decrypt/2 -- transport-level frame encryption

The session is held as an opaque NIF resource (ResourceArc). State transitions happen in-place behind a mutex -- the same reference is used throughout.

Summary

Types

Opaque NIF resource representing a Noise protocol session.

Functions

Decrypt a ciphertext frame using the transport session.

Encrypt a plaintext frame using the transport session.

Transition the session from Handshake to Transport mode.

Read a handshake message from the peer.

Write the next handshake message.

Initialize a Noise XX initiator session.

Initialize a Noise XX responder session.

Return the number of live NoiseSession NIF resources.

Types

session()

@type session() :: reference()

Opaque NIF resource representing a Noise protocol session.

Functions

decrypt(session, ciphertext)

@spec decrypt(session(), binary()) :: binary()

Decrypt a ciphertext frame using the transport session.

The session maintains an internal read counter for nonce generation. Each call advances the counter. Returns the decrypted plaintext.

Raises if the session is still in handshake mode.

encrypt(session, plaintext)

@spec encrypt(session(), binary()) :: binary()

Encrypt a plaintext frame using the transport session.

The session maintains an internal write counter for nonce generation. Each call advances the counter. Returns ciphertext with appended auth tag.

Raises if the session is still in handshake mode.

finish(session)

@spec finish(session()) :: :ok

Transition the session from Handshake to Transport mode.

Must be called after all three XX pattern messages have been exchanged. After this call, encrypt/2 and decrypt/2 become available.

The same session reference is reused -- the internal state transitions in-place.

handshake_read(session, message)

@spec handshake_read(session(), binary()) :: binary()

Read a handshake message from the peer.

Advances the handshake state machine by processing an incoming message. Returns the decrypted payload extracted from the message.

Raises if the session is already in transport mode.

handshake_write(session, payload)

@spec handshake_write(session(), binary()) :: binary()

Write the next handshake message.

Advances the handshake state machine and produces an outgoing message containing the encrypted payload. Returns the message bytes to send.

Raises if the session is already in transport mode.

init(prologue, opts \\ [])

@spec init(
  binary(),
  keyword()
) :: session()

Initialize a Noise XX initiator session.

The prologue is mixed into the handshake hash for channel binding. Both sides must use the same prologue for the handshake to succeed.

Returns an opaque session reference for use with handshake_write/2.

init_responder(prologue, opts \\ [])

@spec init_responder(
  binary(),
  keyword()
) :: session()

Initialize a Noise XX responder session.

Used for testing full handshake flows. Production WhatsApp connections only use the initiator side -- the server is the responder.

session_count()

@spec session_count() :: non_neg_integer()

Return the number of live NoiseSession NIF resources.

Tracked via an atomic counter on the Rust side: incremented on creation, decremented on Drop. Used by leak verification tests to confirm that the BEAM garbage collector properly frees ResourceArc resources.