The problem it solves
Messages are encrypted with symmetric keys, and a symmetric key only helps if both ends have it. Two devices that have just met share nothing but an open channel, which anyone nearby or along the route may be watching. Diffie-Hellman key agreement lets them create a shared secret anyway, by each publishing one value and keeping another back.
RFC 7748 specifies two elliptic curves for this, curve25519 and curve448, intended to operate at around the 128-bit and 224-bit security levels respectively. X25519 is the name of the Diffie-Hellman function on curve25519. The RFC says both curves lend themselves to constant-time implementation and resist a wide range of side-channel attacks, including timing and cache attacks. If public and private keys are new to you, start there.
How the exchange works
The X25519 function takes a secret number and a point on the curve, written as a u-coordinate, and returns another u-coordinate. Inputs and outputs are 32-byte strings. RFC 7748 then describes the exchange between Alice and Bob:
- Alice generates 32 random bytes, her private key a, and sends Bob K_A = X25519(a, 9). The 9 is the u-coordinate of the curve’s agreed base point.
- Bob does the same with his own random b and sends Alice K_B = X25519(b, 9).
- Alice computes X25519(a, K_B). Bob computes X25519(b, K_A).
- Both results are the same value, K. They run K, together with K_A and K_B, through a key-derivation function to produce the symmetric keys they will actually use.
Someone watching sees K_A and K_B but neither private key, and the security of the exchange rests on K not being practically computable from those two public values. The shared secret itself is never transmitted.
Checks an implementation should make
The arithmetic is short, but RFC 7748 and the protocols that use it add some care:
- The all-zero result. If one side sends a specially chosen point of small order, X25519 outputs all zeros and the other side’s private key contributes nothing. RFC 7748 says parties MAY check for this and abort. TLS 1.3 (RFC 8446) makes the check mandatory.
- No contribution guarantee. Because of this, RFC 7748 warns designers not to assume that both parties’ private keys always contribute to the shared key.
- Equivalent public keys. Several different public keys can produce the same shared secret. The RFC warns that treating a public key as an identifier, and knowledge of the shared secret as proof of owning it, can lead to subtle vulnerabilities unless the public keys go into the key derivation. That is one reason step 4 includes K_A and K_B.
Key exchange does not tell you who is on the other end
X25519 guarantees that the two parties who completed the exchange share a secret. It says nothing about who those parties are. Signal’s X3DH specification is direct about this: if the parties do not authenticate each other’s identity keys, they receive no cryptographic guarantee as to who they are communicating with. TLS 1.3 says the same of unauthenticated public keys: on their own they are vulnerable to man-in-the-middle attacks.
Protocols close that gap in a few ways:
- Sign the exchange. A long-term signing key, such as an Ed25519 key, signs the ephemeral public values or the handshake, and the other side verifies that signature against a key it trusts.
- Mix in long-term keys. X3DH combines several Diffie-Hellman results that involve each side’s identity key, which gives mutual authentication.
- Verify keys out of band. People compare key fingerprints or scan a QR code in person, or use trust on first use and warn if a key changes.
Fresh keys and forward secrecy
Generating an X25519 key pair takes only 32 random bytes, so a protocol can create a new pair for each session and delete the private half afterwards. In X3DH, Alice deletes her ephemeral private key and the Diffie-Hellman outputs once the shared key is derived, and the specification credits the ephemeral and one-time exchanges with providing forward secrecy.
Where X25519 is used
- TLS 1.3 lists x25519 among its key exchange groups and says implementations SHOULD support it.
- Signal’s X3DH uses X25519 or X448 as its curve.
- MLS (RFC 9420) has a mandatory cipher suite that uses curve25519 for key exchange, through the DHKEM(X25519, HKDF-SHA256) mechanism defined in Hybrid Public Key Encryption (RFC 9180), with Ed25519 for signatures. MLS requires the encryption key and the signature key in each member’s entry to be distinct.
X25519 and Ed25519 sit on related forms of the same curve, but one key agrees secrets and the other signs, and protocols such as MLS keep them apart.