βοΈ Two Gears Turning
Combined Double Ratchet Systemβ
In 20 minutes: See how symmetric and DH ratchets work together
Prerequisites: Symmetric Key Ratchet + DH Ratchet
π― The Simple Storyβ
The Double Ratchet = 2 ratchets working together!
- Symmetric ratchet: Every message β KDF for K_i β β use β delete
- DH ratchet: When responding β new DH β update RK β new chain keys
Both ratchets = Maximum forward secrecy!
π§ Mental Modelβ
Hold this picture in your head:
Double Ratchet:
Alice sends Message 1:
ββ Symmetric ratchet: K1 = KDF_C(CK_A1) β Use β Delete
ββ No DH ratchet (just sending)
Bob responds (Message 2):
ββ Symmetric ratchet: K2 = KDF_C(CK_B2) β Use β Delete
ββ DH ratchet triggers:
DH RANCHET (both perform):
Alice: Alice_EK_new, Bob_EK_new_pub
Bob: Bob_EK_new, Alice_EK_new_pub
DH_new = Alice_EK_new Γ Bob_EK_new
RK_new = KDF(DH_new)
CK_A_new = KDF(RK_new)
CK_B_new = KDF(RK_new)
Alice sends Message 3:
ββ Symmetric: K3 = KDF_C(CK_A_new) β Use β Delete
ββ No DH ratchet (already refreshed)
Bob responds (Message 4):
ββ Symmetric: K4 = KDF_C(CK_B_new) β Use β Delete
ββ DH ratchet triggers again!
Repeat: DH ratchet only on responses
Think of it like:
βοΈ Two gears (Symmetric per message, DH per response)
π Continuous rotation (Never stop both)
π Layered security (One fails? Other protects!)
π See It Happenβ
Complete flow:
π― Timing of Ratchetsβ
Symmetric ratchet: Every message (send and receive)
DH ratchet: Only when responding (Bob's turn first)
Msg 1 Alice β Bob: Symmetric ratchet (K1)
Msg 2 Bob β Alice: Symmetric ratchet (K2) + DH ratchet (update RK)
Msg 3 Alice β Bob: Symmetric ratchet (K3)
Msg 4 Bob β Alice: Symmetric ratchet (K4) + DH ratchet (update RK again)
Msg 5 Alice β Bob: Symmetric ratchet (K5)
...
π’ The Mathβ
Combined Algorithmβ
# Initial state (after X3DH)
RK
# Message 1 (Alice β Bob):
K1 = KDF_C(CK_A1)
Encrypt(msg1, K1) β ciphertext1
Delete K1
# Message 2 (Bob β Alice):
# Bob wants to respond β trigger DH ratchet
# DH ratchet
Bob_EK_private, Bob_EK_public β Generate
Alice_EK_public β from ciphertext1 metadata
DH_new = Bob_EK_private Γ Alice_EK_public
RK_new = KDF(DH_new)
CK_A_new = KDF(RK_new)
CK_B_new = KDF(RK_new)
# Delete old RK, CK_A, CK_B
# Now symmetric ratchet
K2 = KDF_C(CK_B_new)
Encrypt(msg2, K2) β ciphertext2
Delete K2
# Message 3 (Alice β Bob):
# No DH response, just symmetric
K3 = KDF_C(CK_A_new)
Encrypt(msg3, K3) β ciphertext3
Delete K3
# Message 4 (Bob β Alice):
# Bob responding again β DH ratchet
# DH ratchet again (same process)
Bob_EK_private_2, Bob_EK_public_2 β Generate
Alice_EK_public_2 β from ciphertext3 metadata
DH_new_2 = Bob_EK_private_2 Γ Alice_EK_public_2
RK_new_2 = KDF(DH_new_2)
CK_A_new_2 = KDF(RK_new_2)
CK_B_new_2 = KDF(RK_new_2)
# Delete old RK_new, CK_A, CK_B
K4 = KDF_C(CK_B_new_2)
Encrypt(msg4, K4) β ciphertext4
Delete K4
π‘ Why Both Ratchets?β
Symmetric Ratchet Benefitsβ
- Efficient (no DH per message)
- Fast (KDF vs DH expensive)
- Works for every message
DH Ratchet Benefitsβ
- Fresh keys regularly (post-compromise security)
- Recover from compromise (limited damage)
- Adds entropy regularly
Combinedβ
β
Every message has new key (symmetric)
β
Compromise limited (DH on responses)
β
Efficient and fast
β
Maximum forward secrecy
β Quick Checkβ
Why both ratchets?
Complementary benefits:
Symmetric: Efficient, per message DH: Fresh keys regularly, post-compromise
Combined: Best of both!
When does DH ratchet trigger?
Only on responses:
Msg 1 (AliceβBob): No DH Msg 2 (BobβAlice): DH ratchet triggers (Bob responds) Msg 3 (AliceβBob): No DH Msg 4 (BobβAlice): DH ratchet triggers (Bob responds)
π Key Takeawaysβ
β
Symmetric ratchet: Every message β K_i
β
DH ratchet: Only on responses β RK renewal
β
Combined: Both work together
β
Efficiency: Symmetric for speed, DH for freshness
β
Maximum security: Forward secrecy + post-compromise recovery
β
Timing: DH on first response per conversation segment
π Congratulations!β
You've completed the Double Ratchet section!
Next: Practical implementation.