CRYPTOGRAPHIC FOUNDATION

Forward Secrecy & Cryptographic Foundation

How C6P v1 ensures that compromising current cryptographic state cannot reveal past messages through per-message key derivation, symmetric ratcheting, and production-grade AEAD.

ChaCha20
Production AEAD
256-bit
Keys
Per-Msg
Ephemeral
Fail-Closed
By Design

What is Forward Secrecy?

Protection against past message compromise, even when current state is breached.

Forward secrecy (also called "perfect forward secrecy") is a property of secure communication protocols where the compromise of long-term keys does not compromise past session keys. In the context of C6P v1, this means:

Unique Ephemeral Keys

Each message uses a unique ephemeral key derived from a chain key that's never transmitted

Immediate Key Deletion

Keys are deleted immediately after use — there's no way to recover them

Future-Only Compromise

Compromise of current state reveals only future messages, not past ones

Device Seizure Protection

Even if an attacker gains access to your device today, they cannot decrypt messages sent yesterday

Real-World Impact

If your phone is seized by law enforcement or compromised by malware, past conversations remain secure. The attacker can only read new messages going forward, assuming the compromise persists.

The Symmetric Ratchet Mechanism

One-way chain key advancement that never allows backward computation.

C6P v1 implements a symmetric ratchet (also called a "hash ratchet") that advances forward with each message. Unlike asymmetric ratchets (like in Signal's Double Ratchet), this ratchet doesn't require new Diffie-Hellman exchanges per message.

How It Works: The Chain Key Dance

1. Start with Initial Chain Key (CK₀)
↓ HKDF-Extract + HKDF-Expand
2. Derive Message Key (MK₁) for counter=1
↓ Encrypt message
3. Derive Next Chain Key (CK₁) from same PRK
↓ Delete CK₀ and MK₁ immediately
4. CK₁ becomes new base for counter=2
↓ Repeat forever...
Critical Security Property

The chain key derivation is one-way. Given CK₁₀, you cannot compute CK₉. This ensures that compromising the current state doesn't reveal past keys. The ratchet only moves forward, never backward.

Per-Stream State Management

Each C6P session maintains two independent ratchets:

Stream Direction Purpose
i2r (0x01) Initiator → Responder Initiator sends, responder receives
r2i (0x02) Responder → Initiator Responder sends, initiator receives

Cryptographic Key Derivation

HKDF-based derivation with domain-separated labels for security.

Every message key is derived through a carefully designed process using HKDF (HMAC-based Key Derivation Function) with domain-separated labels to prevent key reuse across different contexts.

The Derivation Process

Normative Key Derivation (from c6p-key-schedule.md §6)
// Step 1: Create message-specific salt
salt_msg = SHA256("C6P_MSG_V1" || CTX || transcript_hash ||
                   STREAM_CTX || BE64(counter))

// Step 2: Extract pseudorandom key from chain key
prk_msg = HKDF-Extract(salt=salt_msg, ikm=CK)

// Step 3: Expand to message key material
mk_material = HKDF-Expand(prk_msg,
                          info="C6P_MSG_V1" || U8(0x01) || STREAM_CTX,
                          L=32)

// Step 4: Map to cipher suite key
suite_key = map_to_suite_key(mk_material, suite_id)

// Step 5: Derive deterministic nonce
nonce = derive_nonce(mk_material, counter, suite_id, session_binding)

// Step 6: Derive next chain key (from same prk_msg)
CK_next = HKDF-Expand(prk_msg,
                      info="C6P_CHAIN_V1" || U8(0x01) || STREAM_CTX || BE64(counter),
                      L=32)
Domain Separation

The labels "C6P_MSG_V1" and "C6P_CHAIN_V1" are normative. Custom labels break interoperability and security guarantees.

AEAD Cipher Suites

Production-grade Authenticated Encryption with Associated Data for message protection.

ChaCha20-Poly1305: Production Default

C6P v1 uses ChaCha20-Poly1305 as the default and required AEAD cipher. This is a modern, high-performance authenticated encryption algorithm that's battle-tested and widely deployed.

Suite Suite ID Key Nonce Tag Status
ChaCha20-Poly1305 0x01 32 bytes 12 bytes 16 bytes REQUIRED
XChaCha20-Poly1305 0x02 32 bytes 24 bytes 16 bytes OPTIONAL
AEGIS-128L 0x03 16 bytes 16 bytes 16 bytes GATED

Why ChaCha20-Poly1305?

High Performance

Optimized for modern CPUs without AES-NI — faster on mobile devices

Battle-Tested

Used by TLS 1.3, WireGuard, Signal — proven in production

Constant-Time

Resistant to timing attacks — no secret-dependent branches

Simple Design

Easy to implement correctly — fewer opportunities for bugs

Optional Suites

XChaCha20-Poly1305 (extended 24-byte nonce) and AEGIS-128L (high-performance hardware-accelerated) are optional in v1. All implementations MUST support ChaCha20-Poly1305 (0x01).

Deterministic Nonce Derivation

Safe by construction — no randomness needed, no nonce reuse possible.

Why Deterministic Nonces Are Safe

C6P uses deterministic nonces — derived from message context, not random. This is safe because:

1
Per-Message Keys

Every message uses a unique AEAD key derived from (session, stream, counter, type, suite)

2
Context-Bound Derivation

Nonce binds to all message context — replay detection prevents duplicate counters

3
Explicit Replay Rejection

Even if AEAD verifies, duplicate (session, stream, counter) is rejected

Canonical Nonce Construction

Deterministic Nonce Derivation
// Step 1: PRK from session binding + message key material
prk_nonce = HKDF-Extract(
    salt = session_binding,
    ikm = mk_material
)

// Step 2: Info binding all message context
info = "C6P_NONCE_V1" ||
       U8(C6P_VERSION) ||
       U8(suite_id) ||
       U8(message_type) ||
       U8(stream_id) ||
       session_id(8) ||
       BE64(counter)

// Step 3: Expand to suite-specific nonce length
nonce = HKDF-Expand(prk_nonce, info, L=nonce_len)

// Nonce lengths per suite:
// ChaCha20-Poly1305:   12 bytes
// XChaCha20-Poly1305:  24 bytes
// AEGIS-128L:          16 bytes
Security Guarantee

The same (suite_key, nonce) pair is mathematically impossible to reuse. Counter uniqueness is enforced by the protocol state machine, and any violation triggers fail-closed rejection.

Tag Verification & Fail-Closed Design

Production-grade security through strict validation and fail-closed error handling.

Authentication Tag Verification

All C6P AEAD suites produce a 16-byte authentication tag. This tag cryptographically proves that:

Authenticity

Message was created by someone with the session key

Integrity

Ciphertext hasn't been tampered with

AAD Binding

Metadata (suite, stream, counter) is authentic

Context Lock

Message can't be moved to different session

Fail-Closed Philosophy

C6P follows a fail-closed security model: when anything goes wrong, the system rejects the message rather than trying to recover.

Decryption & Verification Flow
1. Validate envelope structure
↳ Known suite_id, stream_id, message_type
2. Reconstruct AAD from envelope + session state
↳ Must be exactly 63 bytes
3. Derive suite_key and nonce
↳ From mk_material for this counter
4. AEAD_Open(key, nonce, aad, sealed)
↳ Tag verification happens here
5. IF tag invalid → REJECT
↳ Do NOT advance ratchet, do NOT mark consumed
6. IF tag valid BUT counter replay → REJECT
↳ Even if decryption succeeds!
7. IF all checks pass → Accept & advance state

Violation Response

Tag Verification Failed

Message rejected, state unchanged, security event logged

Unknown Suite ID

Rejected before any crypto operations

Malformed Sizes

Wrong session_id length, sealed too short, AAD mismatch

Counter Replay

Duplicate counter detected — rejected even if AEAD verifies

Hard Rule: No Recovery Attempts

C6P implementations MUST NOT "try to recover" from cryptographic failures by guessing counters, accepting replays, or weakening validation. All violations trigger fail-closed rejection. This is non-negotiable for security.

Key Takeaways

Forward secrecy protects past messages even if current state is compromised

Symmetric ratchet advances one-way — past keys unrecoverable

ChaCha20-Poly1305 production default — fast, battle-tested, constant-time

Deterministic nonces safe by construction — per-message keys prevent reuse

16-byte tags cryptographically prove authenticity and integrity

Fail-closed design — violations rejected, no recovery attempts