# `ExWapp.Signal.Session`
[🔗](https://github.com/elchemista/ex_wapp/blob/v0.1.5/lib/ex_wapp/signal/session.ex#L1)

Signal Protocol session management for WhatsApp encryption.

Implements:
- X3DH (Extended Triple Diffie-Hellman) key agreement
- Double Ratchet Algorithm for forward secrecy
- AES-256-CBC + HMAC-SHA256 message encryption (proper Signal format)

# `chain_state`

```elixir
@type chain_state() :: %{
  key: binary(),
  counter: non_neg_integer(),
  message_keys: %{required(non_neg_integer()) =&gt; binary()}
}
```

# `encrypted_message`

```elixir
@type encrypted_message() :: %{
  type: :prekey_message | :message,
  registration_id: non_neg_integer(),
  prekey_id: non_neg_integer() | nil,
  signed_prekey_id: non_neg_integer(),
  base_key: binary() | nil,
  identity_key: binary(),
  ciphertext: binary()
}
```

# `session_state`

```elixir
@type session_state() :: %{
  optional(:initiator_base_key) =&gt; binary(),
  remote_identity_key: binary(),
  local_identity_key: %{public: binary(), private: binary()},
  root_key: binary(),
  sending_chain: chain_state() | nil,
  receiving_chain: chain_state() | nil,
  receiving_chains: %{optional(binary()) =&gt; chain_state()},
  previous_counter: non_neg_integer(),
  ratchet_key: %{public: binary(), private: binary()} | nil,
  remote_ratchet_key: binary() | nil
}
```

# `create_session`

```elixir
@spec create_session(map(), map()) ::
  {:ok, session_state(), binary()} | {:error, term()}
```

Creates a new session using X3DH key agreement.

Uses the recipient's prekey bundle to establish a shared secret.

# `decrypt`

```elixir
@spec decrypt(session_state(), binary()) ::
  {:ok, binary(), session_state()} | {:error, term()}
```

Decrypts a regular Signal message.

# `decrypt_prekey_message`

```elixir
@spec decrypt_prekey_message(binary(), map(), map()) ::
  {:ok, binary(), session_state()} | {:error, term()}
```

Decrypts a PreKeySignalMessage (initial message from a new sender).

# `decrypt_prekey_message_with_session`

```elixir
@spec decrypt_prekey_message_with_session(session_state(), binary()) ::
  {:ok, binary(), session_state()} | {:error, term()}
```

Decrypts a PreKeySignalMessage using an already-established session.

WhatsApp can keep wrapping sync traffic as `pkmsg` even when a session already exists.
In that case, we must decrypt the inner SignalMessage with the current ratchet state
instead of re-running X3DH and replacing the session.

# `encrypt`

```elixir
@spec encrypt(session_state(), binary()) :: {:ok, binary(), session_state()}
```

Encrypts a message using the session.

Returns the encrypted ciphertext and updated session state.
Uses proper Signal Protocol wire format with AES-CBC + HMAC.

# `encrypt_prekey_message`

```elixir
@spec encrypt_prekey_message(session_state(), binary(), map()) ::
  {:ok, binary(), session_state()}
```

Encrypts a message and returns a PreKeySignalMessage for initial messages.
Uses proper Signal Protocol wire format.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
