diff --git a/advanced/signal-protocol.mdx b/advanced/signal-protocol.mdx index 5e2ab8d5..64256d2c 100644 --- a/advanced/signal-protocol.mdx +++ b/advanced/signal-protocol.mdx @@ -982,6 +982,24 @@ pub fn derive_keys(secret_input: &[u8]) -> (RootKey, ChainKey, InitialPQRKey) { Location: `wacore/libsignal/src/protocol/ratchet.rs:18-39` +### X25519 key agreement + +`calculate_agreement` runs during session setup, and again whenever the session performs a DH ratchet step — when an incoming message carries a remote ratchet key the local session hasn't chained on yet. `get_or_create_chain_key` calls `RootKey::create_chain` once to derive the new receiving chain; `DeferredSenderRatchet::apply` then calls it a second time, with a freshly generated local key, to derive the new sending chain. Each `create_chain` call performs exactly one agreement, so a single DH ratchet step costs two. Messages within an already-open chain advance via `ChainKey::step_with_message_keys` instead, which costs none. + +```rust +pub fn calculate_agreement(&self, their_key: &PublicKey) -> Result<[u8; 32], CurveError> +``` + +Location: `wacore/libsignal/src/core/curve.rs` + +As of PR #1218, `calculate_agreement` routes through `SignalCryptoProvider::x25519_agreement`. AES-256-CBC above uses the same pluggable crypto-provider hook; HKDF-SHA256 does not — it always calls `hkdf::Hkdf` directly. Override the hook with `set_crypto_provider` (`wacore/libsignal/src/crypto/provider.rs`) to run the agreement on another backend. The default is this crate's own implementation, and it cannot fail. + +If you install a backend that can refuse the operation, you see the refusal as `CurveError::AgreementFailed`. Through `SignalProtocolError`, it reaches you as `KeyAgreementFailed`. The decrypt path treats a refusal as a local failure, not message corruption: it takes priority over the MAC-based verdicts (`InvalidMessage`, `BadMac`). + + +Call `set_crypto_provider` before any crypto call, key agreement included. The provider installs once — a call made after the default provider has already initialized returns an error instead of replacing it. + + ## PreKey Management Pre-keys enable asynchronous session establishment in the Signal Protocol. whatsapp-rust manages pre-key generation and upload to match WhatsApp Web's behavior.