Forward Secrecy

Compromising today's keys does not reveal yesterday's messages.

What Forward Secrecy Means

Forward secrecy (also called perfect forward secrecy, PFS) is a property of a cryptographic protocol where compromise of long-term secret keys does not compromise past session keys. In practical terms: if an attacker obtains your private keys right now, they cannot decrypt messages you sent or received before this moment.

This stands in contrast to protocols without forward secrecy. Consider PGP email encryption: if your PGP private key is compromised, every message ever encrypted to that key becomes readable. Past, present, and future. A single key compromise is a total compromise.

RVNT provides forward secrecy at multiple levels through the Double Ratchet algorithm. Key material is continuously generated, used once, and deleted. The window of exposure for any single key compromise is exactly one message.

How the Ratchet Provides Forward Secrecy

Level 1: Message Key Deletion

Every message is encrypted with a unique message key. After encryption (sender) or decryption (recipient), the message key is securely zeroed from memory. It is never written to disk. It cannot be reconstructed.

Timeline of a message key's existence:

  t=0    chain_key → HMAC-SHA256 → message_key
  t=1    message_key used to encrypt message
  t=2    secure_zero(message_key)    ← key is gone forever
  t=3    message_key does not exist in RAM, disk, or anywhere

Even if an attacker captures a full memory dump at t=3,
they cannot find message_key. It has been overwritten.

Level 2: Chain Key Advancement

The chain key advances after each message via a one-way function. Given chain_key[n+1], it is computationally infeasible to derive chain_key[n] or any previous chain key.

chain_key[0] → chain_key[1] → chain_key[2] → chain_key[3] → ...
     │               │               │               │
   msg_key[0]     msg_key[1]     msg_key[2]     msg_key[3]
   (deleted)      (deleted)      (deleted)      (current)

Forward direction (trivial):
  chain_key[3] → chain_key[4] → ...

Backward direction (infeasible):
  chain_key[3] → chain_key[2]   ✗ IMPOSSIBLE
  chain_key[3] → msg_key[0]     ✗ IMPOSSIBLE

The chain key function is HMAC-SHA256, which is a PRF.
PRFs are not invertible. Knowing the output does not reveal the input.

Level 3: DH Ratchet (Break-In Recovery)

The DH ratchet generates entirely new key material when the conversation direction changes. Even if an attacker compromises the current chain key, the next DH ratchet step produces a new chain key that the attacker cannot derive.

State at time of compromise:
  Attacker knows: chain_key[current], root_key[current]
  Attacker can: decrypt remaining messages in current chain

DH Ratchet step occurs (other party replies):
  new_dh_private = X25519.generate()       // attacker doesn't know this
  dh_output = DH(new_dh_private, remote_pub)
  root_key[new], chain_key[new] = HKDF(root_key, dh_output)

  Attacker cannot compute:
    - new_dh_private  (generated randomly, never transmitted)
    - dh_output       (requires new_dh_private)
    - root_key[new]   (requires dh_output)
    - chain_key[new]  (requires root_key[new])

Result: The session "heals" after the next DH ratchet step.
The attacker's window of access is closed.

Concrete Example

Day 1: Alice and Bob exchange 50 messages
        50 unique message keys generated and deleted
        5 DH ratchet steps performed

Day 2: Attacker compromises Alice's device
        Attacker obtains current ratchet state:
          - root_key (current)
          - send_chain_key (current)
          - recv_chain_key (current)
          - dh_self (current keypair)

What attacker CAN decrypt:
  ✓ Messages in the current sending chain (not yet ratcheted)
  ✓ Messages in the current receiving chain (not yet ratcheted)

What attacker CANNOT decrypt:
  ✗ Any of the 50 messages from Day 1
    (message keys deleted, chain keys advanced, DH keys deleted)
  ✗ Previous chain keys (one-way function)
  ✗ Previous root keys (one-way function + deleted DH keys)

What happens next:
  Day 3: Bob sends a reply → DH ratchet step
         New root_key and chain_key derived from fresh DH
         Attacker's compromise is healed
         Even future messages become unreadable to the attacker

Key Deletion Implementation

Forward secrecy is only as strong as the key deletion mechanism. If "deleted" keys persist in memory, swap, or disk, forward secrecy is undermined.

Memory Zeroing

RVNT uses the zeroize crate (Rust) for secure key deletion:

use zeroize::{Zeroize, ZeroizeOnDrop};

// [derive ZeroizeOnDrop]
struct MessageKey([u8; 32]);

// When MessageKey is dropped (goes out of scope), the zeroize
// implementation overwrites the 32 bytes with zeros using
// volatile writes and a compiler barrier.

// Volatile writes prevent the compiler from optimizing away
// the zeroing operation (dead-store elimination).

// The compiler barrier (core::sync::atomic::compiler_fence)
// prevents instruction reordering across the barrier.

Memory Locking

// On platforms that support it, key material pages are mlock'd
// to prevent them from being swapped to disk:

// [cfg unix]
unsafe {
    libc::mlock(key_ptr as *const libc::c_void, key_len);
}

// This ensures the key material stays in RAM and is never
// written to the swap file/partition, where it could persist
// after being "deleted" from application memory.

Database Key Handling

Ratchet state stored in SQLCipher database:
  1. Database encrypted with Argon2id-derived key
  2. Old chain keys are overwritten (not just deleted) when advanced
  3. SQLCipher uses PRAGMA secure_delete = ON
     (zeroes deleted data pages instead of just marking them free)
  4. Message keys are NEVER stored in the database
     (they exist only in memory, for the duration of one encrypt/decrypt)

Comparison: Forward Secrecy Across Systems

SystemForward SecrecyGranularityBreak-In Recovery
PGP/GPG None N/A None (key compromise = total compromise)
TLS 1.3 Per-session Session (may be hours) Per-session (new handshake)
Signal Protocol Per-message Single message Per DH ratchet step
RVNT Per-message Single message Per DH ratchet step + PQ hybrid

What Forward Secrecy Does Not Protect Against

  • Real-time surveillance: If an attacker is reading your messages as you send them (e.g., malware on your device), forward secrecy is irrelevant. They see the plaintext before it is encrypted.
  • Recipient retention: Forward secrecy protects keys and transport. It does not prevent the recipient from storing, forwarding, or screenshotting decrypted messages.
  • Metadata: Forward secrecy protects message content. Metadata (who, when, how often) requires separate protection (sealed sender, Tor, cover traffic).
  • Backup compromise: If you back up your database and the backup is later compromised, the attacker has the database key and all stored messages. RVNT does not create cloud backups for this reason.
Forward secrecy is not a feature you turn on. It is an emergent property of the Double Ratchet's key management. Every message you send through RVNT automatically benefits from forward secrecy. There is no configuration needed, and it cannot be disabled.

Further Reading

Last updated: 2026-04-12

RVNT Documentation — Post-quantum encrypted communications