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.
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
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
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
// 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)
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?
Optimized for modern CPUs without AES-NI — faster on mobile devices
Used by TLS 1.3, WireGuard, Signal — proven in production
Resistant to timing attacks — no secret-dependent branches
Easy to implement correctly — fewer opportunities for bugs
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:
Every message uses a unique AEAD key derived from (session, stream, counter, type, suite)
Nonce binds to all message context — replay detection prevents duplicate counters
Even if AEAD verifies, duplicate (session, stream, counter) is rejected
Canonical Nonce Construction
// 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
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:
Message was created by someone with the session key
Ciphertext hasn't been tampered with
Metadata (suite, stream, counter) is authentic
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.
Violation Response
Message rejected, state unchanged, security event logged
Rejected before any crypto operations
Wrong session_id length, sealed too short, AAD mismatch
Duplicate counter detected — rejected even if AEAD verifies
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