# Post-Compromise Security

Post-compromise security (PCS) is a property of a cryptographic protocol that
guarantees: **after an attacker compromises a participant's state, the protocol
automatically heals so that future messages are protected.** The attacker's
window of access is limited to the current epoch; once the compromised member (or
any other member) issues an Update or Commit, the group state is re-randomized
and the attacker is locked out.

PCS is the complement of [forward secrecy](forward-secrecy.md):

- **Forward secrecy** protects the **past** from a future compromise.
- **Post-compromise security** protects the **future** from a past compromise.

MLS (RFC 9420) is specifically designed to provide both properties simultaneously
for group messaging. This is a key differentiator of quicproquo's design.

## How MLS Provides PCS

### The Ratchet Tree

At the heart of MLS's PCS mechanism is the **ratchet tree**, a binary tree where:

- Each **leaf** represents a group member and contains their public key material.
- Each **internal node** holds derived key material computed from its children.
- The **root** of the tree determines the epoch's group key material.

```text
             [Root]
            /      \
         [A,B]    [C,D]
         /   \    /   \
       [A]  [B] [C]  [D]
```

When a member updates their leaf (by generating fresh key material and issuing an
Update proposal or Commit), the change propagates up the tree path from the leaf
to the root:

```text
             [Root]*        <- re-derived
            /      \
         [A,B]*   [C,D]    <- re-derived
         /   \    /   \
       [A]*  [B] [C]  [D]  <- A updated leaf
```

Every node marked with `*` receives new key material. This means the new epoch's
group secrets depend on A's freshly generated randomness. An attacker who
previously compromised A's state must now also compromise the new key material --
which they cannot do because it was generated after the compromise was detected
(or automatically healed by the protocol).

### Cost

The path from a leaf to the root has length O(log n) for a group of n members.
This means:

- An Update/Commit produces O(log n) encrypted path secrets.
- Each group member processes the Update in O(log n) time.
- This is dramatically more efficient than pairwise rekeying (O(n)) or
  broadcast encryption.

For a group of 1,000 members, the path length is approximately 10 nodes --
making PCS practical even for large groups.

## Epoch Advancement in quicproquo

In the current implementation, epoch advancement occurs through the `GroupMember`
methods in `group.rs`:

### Adding a Member (Commit)

When `add_member()` is called, openmls creates a Commit that adds the new member
and updates the ratchet tree:

```rust
// Alice adds Bob -- this creates a Commit + Welcome
let (commit_bytes, welcome_bytes) = alice.add_member(&bob_kp)?;

// Alice merges the pending Commit, advancing her epoch
// Internally, openmls re-derives the ratchet tree with Bob's leaf
group.merge_pending_commit(&self.backend)?;
```

After `merge_pending_commit()`, Alice's group is in a new epoch with fresh key
material. Any attacker who had compromised Alice's state before this Commit
must now also compromise the new epoch's keys.

### Receiving a Commit

When a member receives and processes a Commit from another member:

```rust
ProcessedMessageContent::StagedCommitMessage(staged) => {
    // Merge the Commit into local state -- epoch advances
    group.merge_staged_commit(&self.backend, *staged)?;
    Ok(None)
}
```

This advances the receiver's epoch, incorporating the committer's fresh key
material into the ratchet tree.

### Future: Periodic Updates

The current implementation only advances epochs when members are added. A more
robust PCS strategy involves periodic Update proposals, where members
re-randomize their leaf key material on a regular schedule (e.g., every hour, or
every N messages). This is planned for future milestones and will look like:

```text
1. Member generates fresh leaf key material
2. Member creates an Update proposal
3. Any member (or the updater) creates a Commit including the Update
4. All members process the Commit and advance to the new epoch
5. The attacker's compromised state is now stale
```

## PCS vs Forward Secrecy

These two properties are often confused but protect against different attack
scenarios:

| Property | Protects | Mechanism | Threat |
|----------|----------|-----------|--------|
| Forward Secrecy | Past messages | Delete old epoch keys | Attacker compromises state **now**, tries to read **past** |
| Post-Compromise Security | Future messages | Re-randomize ratchet tree | Attacker compromised state **before**, tries to read **future** |

Together, they provide a strong guarantee: the attacker's window of access is
limited to the **current epoch only**. Past epochs are protected by FS (old keys
deleted), and future epochs are protected by PCS (new key material generated).

```text
     Past epochs          Current epoch         Future epochs
  +-----------------+  +-----------------+  +-----------------+
  |  Protected by   |  |  Attacker has   |  |  Protected by   |
  |  Forward        |  |  access if they |  |  Post-Compromise|
  |  Secrecy        |  |  hold current   |  |  Security       |
  |  (keys deleted) |  |  epoch keys     |  |  (tree updated) |
  +-----------------+  +-----------------+  +-----------------+
```

## Comparison with Signal Groups

Signal's group messaging uses **Sender Keys**, a fundamentally different
mechanism from MLS's ratchet tree. The comparison is instructive because it
highlights why MLS was chosen for quicproquo:

### Signal Sender Keys

In Signal's group protocol:

1. Each member generates a Sender Key -- a symmetric key used to encrypt all
   messages they send to the group.
2. The Sender Key is distributed to all group members via pairwise Signal
   sessions.
3. Each message from a sender is encrypted with their Sender Key.
4. The Sender Key includes a symmetric ratchet (hash ratchet) that advances per
   message, providing forward secrecy within a sender's chain.

**The critical limitation:** Sender Keys do **not** provide post-compromise
security. If an attacker compromises a member's Sender Key:

- The attacker can derive all future message keys from that sender (the hash
  ratchet is one-way, but the attacker has the current state).
- The key is only rotated when the member manually refreshes it or when group
  membership changes.
- There is no automatic healing mechanism analogous to MLS's ratchet tree.

### MLS Ratchet Tree (quicproquo)

In contrast, MLS's ratchet tree provides PCS because:

1. Any member can issue an Update that re-randomizes their leaf.
2. The Commit propagates new key material up the tree, affecting the group
   secret.
3. The attacker, who holds old state, cannot predict the new randomness.
4. The group automatically heals after at most one epoch advance.

| Property | Signal Sender Keys | MLS Ratchet Tree |
|----------|-------------------|-----------------|
| Forward secrecy (group) | Per-sender hash ratchet | Per-epoch (Commit) |
| Post-compromise security | **No** -- compromised Sender Key reveals all future messages from that sender | **Yes** -- any Commit/Update heals the tree |
| Key rotation | Manual or on membership change | Any Commit (add/remove/update) |
| Healing time | Until manual rotation | Next epoch (automatic) |
| Cost per update | O(n) pairwise re-encryption | O(log n) tree path |

## Practical Implications

### What happens during a compromise?

Suppose an attacker compromises Member A's MLS state (including the current epoch
keys):

1. **Current epoch:** The attacker can decrypt all messages in the current epoch
   from all members (because epoch keys are shared group secrets).

2. **Past epochs:** Protected by forward secrecy. Old epoch keys have been
   deleted by openmls.

3. **After the next Commit:** Any member (including A, after recovering) can
   issue a Commit. The ratchet tree is updated with fresh key material. The
   attacker's stale state cannot derive the new epoch keys. The attacker is
   locked out.

### How quickly does healing occur?

In the current implementation, healing occurs whenever:

- A new member is added (`add_member()` issues a Commit).
- A member is removed (not yet implemented, but will issue a Commit).
- In the future: periodic Update proposals are issued on a timer.

The practical healing window is the time between Commits. For active groups
with frequent membership changes, this window is small. For static groups,
periodic Updates (planned) will bound the healing window.

### Server compromise does not prevent PCS

The quicproquo server is MLS-unaware -- it stores and forwards encrypted
MLS messages without access to the group state. A compromised server cannot:

- Prevent PCS by blocking Commits (it could perform denial-of-service, but
  cannot selectively suppress Update proposals without being detected, because
  MLS epoch numbers must be sequential).
- Inject fraudulent Commits (it lacks the signing key of any group member).

See [Threat Model](threat-model.md) for the full analysis of a compromised
server.

## Related Pages

- [Cryptography Overview](overview.md) -- algorithm inventory
- [Forward Secrecy](forward-secrecy.md) -- the complementary property
- [Key Lifecycle and Zeroization](key-lifecycle.md) -- how key deletion enables FS and PCS
- [Threat Model](threat-model.md) -- attacker models including compromised clients
- [Post-Quantum Readiness](post-quantum-readiness.md) -- PQ protection for PCS mechanisms
- [MLS (RFC 9420)](../protocol-layers/mls.md) -- protocol deep dive
