Skip to content
X3DH — Initial Key Agreement
step 1/5

Reading — step 1 of 5

Read

~1 min readFoundations: X3DH

X3DH — Initial Key Agreement

X3DH (Extended Triple Diffie-Hellman) lets Bob start an encrypted session with Alice when she's offline.

Alice publishes (IK_A, SPK_A, OPK_A) to the server. Bob fetches them.

Bob generates ephemeral keypair (EK_B). Computes:

DH1 = DH(IK_B, SPK_A)
DH2 = DH(EK_B, IK_A)
DH3 = DH(EK_B, SPK_A)
DH4 = DH(EK_B, OPK_A)   # if OPK present
SK  = HKDF(DH1 || DH2 || DH3 || DH4)

Why each DH?

  • DH1: authenticates Alice (she has IK_A) and Bob (he has IK_B) at long-term level.
  • DH2: authenticates Alice (IK_A) and proves Bob (EK_B) is fresh.
  • DH3: ensures the server can't substitute a different SPK without DH3 changing.
  • DH4: each session unique; stronger forward secrecy.

Bob sends his initial message including:

  • IK_B (so Alice can identify the sender)
  • EK_B (so Alice can run the matching DHs)
  • which OPK was used (so Alice knows which one to retrieve)
  • ciphertext encrypted with key derived from SK

Alice on receiving:

DH1 = DH(SPK_A, IK_B)
DH2 = DH(IK_A, EK_B)
DH3 = DH(SPK_A, EK_B)
DH4 = DH(OPK_A, EK_B)
SK  = HKDF(DH1 || DH2 || DH3 || DH4)   # same as Bob's

Decrypt. Delete OPK_A from her storage so it can't be reused. Both sides now have a shared SK and proceed to Double Ratchet.

X3DH (X25519 + HKDF-SHA-256) is the standard. Production code: signal-protocol-c, libsignal.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…