Introduction states
The Double Ratchet algorithm is used by two parties to exchange encrypted messages based on a shared secret key. Typically the parties will use some key agreement protocol (such as X3DH 1) to agree on the shared secret key. Following this, the parties will use the Double Ratchet to send and receive encrypted messages.
so X3DH is first used to compute a shared secret (SK).
Section 3.3 explains use of SK to initialize chain
Prior to initialization both parties must use some key agreement protocol to agree on a 32-byte shared secret key SK and Bob's ratchet public key. These values will be used to populate Alice's sending chain key and Bob's root key. Bob's chain keys and Alice's receiving chain key will be left empty, since they are populated by each party's first DH ratchet step.
def RatchetInitAlice(state, SK, bob_dh_public_key):
state.DHs = GENERATE_DH()
state.DHr = bob_dh_public_key
state.RK, state.CKs = KDF_RK(SK, DH(state.DHs, state.DHr))
state.CKr = None
state.Ns = 0
state.Nr = 0
state.PN = 0
state.MKSKIPPED = {}
def RatchetInitBob(state, SK, bob_dh_key_pair):
state.DHs = bob_dh_key_pair
state.DHr = None
state.RK = SK
state.CKs = None
state.CKr = None
state.Ns = 0
state.Nr = 0
state.PN = 0
state.MKSKIPPED = {}
Section 5.1 explains Integration of X3DH
The Double Ratchet algorithm can be used in combination with the X3DH
key agreement protocol 1. The Double Ratchet plays the role of a
"post-X3DH" protocol which takes the session key SK negotiated by X3DH
and uses it as the Double Ratchet's initial root key.
The following outputs from X3DH are used by the Double Ratchet:
The SK output from X3DH becomes the SK input to Double Ratchet
initialization (see Section 3.3).
The AD output from X3DH becomes the AD input to Double Ratchet
encryption and decryption (see Section 3.4 and Section 3.5).
Bob's signed prekey from X3DH (SPKB) becomes Bob's initial ratchet
public key (and corresponding key pair) for Double Ratchet
initialization.
Any Double Ratchet message encrypted using Alice's initial sending
chain can serve as an "initial ciphertext" for X3DH. To deal with the
possibility of lost or out-of-order messages, a recommended pattern is
for Alice to repeatedly send the same X3DH initial message prepended
to all of her Double Ratchet messages until she receives Bob's first
Double Ratchet response message.
An easy explaination by ChatGPT is
The very first chain key in the Double Ratchet algorithm is established through the initial key agreement protocol, such as X3DH (Extended Triple Diffie-Hellman), before the Double Ratchet process begins. Here's how it works:
- Initial Key Agreement: Before Alice and Bob start the Double Ratchet process, they use a key agreement protocol (like X3DH) to derive a shared secret key, denoted as ( SK ). This key is shared between both parties and serves as the initial root key.
- Root Key Initialization: Alice and Bob each initialize their root key (( RK )) using the shared secret key ( SK ). For Alice, the initial chain key for the sending chain (( CK_s )) is derived from the root key and the Diffie-Hellman output computed from her own private key and Bob's public key.
- First Chain Key: This derived chain key (( CK_s )) becomes the first chain key in the sending chain for Alice. Similarly, Bob derives his first chain key for his receiving chain from the same root key and DH output.
Thus, the first chain key is essentially derived from the shared secret ( SK ) established during the initial key agreement and the DH output generated when Alice computes it using Bob's public key.
If you'd like to dive deeper into the process or review the documentation directly, you can refer to the Double Ratchet specification.