X25519(3)
π X25519 β okay bestie, let's talk Curve25519
Welcome to X25519(3), which lives in the Library Functions Manual section, and it's about to be your new hyperfixation. She covers X25519, X25519_keypair, ED25519_keypair, ED25519_sign, and ED25519_verify β aka Elliptic Curve Diffie-Hellman and signature primitives based on Curve25519. No cap, this is the good stuff. π¦
β¨ NAME β¨
X25519, X25519_keypair, ED25519_keypair, ED25519_sign, ED25519_verify β Elliptic Curve Diffie-Hellman and signature primitives based on Curve25519.
πΈ SYNOPSIS πΈ
So you're gonna link against the library libcrypto and pull in the header like this:
#include <openssl/curve25519.h>
Then the whole squad of functions looks like this:
int
X25519(uint8_t out_shared_key[X25519_KEY_LENGTH],
const uint8_t private_key[X25519_KEY_LENGTH],
const uint8_t peer_public_value[X25519_KEY_LENGTH]);
void
X25519_keypair(uint8_t out_public_value[X25519_KEY_LENGTH],
uint8_t out_private_key[X25519_KEY_LENGTH]);
void
ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LENGTH],
uint8_t out_private_key[ED25519_PRIVATE_KEY_LENGTH]);
int
ED25519_sign(uint8_t *out_sig, const uint8_t *message,
size_t message_len,
const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH],
const uint8_t private_key_seed[ED25519_PRIVATE_KEY_LENGTH]);
int
ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[ED25519_SIGNATURE_LENGTH],
const uint8_t public_key[ED25519_PUBLIC_KEY_LENGTH]);
π DESCRIPTION π
Curve25519 is an elliptic curve over a prime field, and she's specified in RFC 7748 section 4.1. The prime field is defined by the prime number 2^255 - 19. Yes, that's the whole vibe. π₯
X25519 is the Diffie-Hellman primitive built from Curve25519, exactly as described in RFC 7748 section 5. And section 6.1 describes the intended use in an Elliptic Curve Diffie-Hellman (ECDH) protocol, iykyk.
X25519() writes a shared key to out_shared_key that's calculated from the given private_key and the peer_public_value by scalar multiplication.
β οΈ Bestie, listen β do not use the shared key directly. Use a key derivation function instead, and also include the two public values as inputs. That part is not optional. π
X25519_keypair() sets out_public_value and out_private_key to a freshly generated public/private key pair. The lore here is kind of iconic:
- First,
out_private_keyis generated witharc4random_buf(3). - Then, the opposite of the masking described in RFC 7748 section 5 is applied to it, to make sure that the generated private key is never correctly masked. The whole purpose? To cause incorrect implementations on the peer side to consistently fail. Correct implementations will decode the key correctly even when it is not correctly masked. It's a vibe check for buggy peers, and they will fail it. π
- Finally,
out_public_valueis calculated fromout_private_keyby multiplying it with the Montgomery base pointuint8_t u[32] = {9}.
The size of a public and private key is X25519_KEY_LENGTH = 32 bytes each.
Ed25519 is a signature scheme using a twisted Edwards curve that is birationally equivalent to Curve25519. She's related. Family. π
ED25519_keypair() sets out_public_key and out_private_key to a freshly generated public/private key pair. First, out_private_key is generated with arc4random_buf(3). Then, out_public_key is calculated from the private key. Iconic, efficient, no notes. β¨
ED25519_sign() signs the message of message_len bytes using the public_key and the private_key, and writes the signature to out_sig.
ED25519_verify() checks that signing the message of message_len bytes using the public_key would indeed result in the given signature. Basically the vibe check function. π
The sizes of a public and private keys are ED25519_PUBLIC_KEY_LENGTH and ED25519_PRIVATE_KEY_LENGTH, which are both 32 bytes, and the size of a signature is ED25519_SIGNATURE_LENGTH = 64 bytes.
π RETURN VALUES π
X25519()andED25519_sign()return1on success or0on error.X25519()can fail if the input is a point of small order. Rude, honestly, but that's the rules. πED25519_sign()always succeeds in LibreSSL, but the API reserves the return value0for memory allocation failure. So like, keep that in mind for the future.ED25519_verify()returns1if the signature is valid or0otherwise.
π¦ SEE ALSO π¦
Also, the reading list, because she did her research π«Ά:
- Daniel J. Bernstein, A state-of-the-art Diffie-Hellman function: How do I use Curve25519 in my own software?, https://cr.yp.to/ecdh.html.
- Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, and Bo-Yin Yang, βHigh-Speed High-Security Signaturesβ, Cryptographic Hardware and Embedded Systems β CHES 2011, Springer, Lecture Notes in Computer Science, vol 6917, https://doi.org/10.1007/978-3-642-23951-9_9, Nara, Japan, September 29, 2011.
β STANDARDS β
And that's the whole page, bestie π This masterpiece came to you from Debian, dated June 8, 2025 β so if you see it in the wild, you know exactly whose name is on it. X25519(3) forever. π
π¦ where this page comes from
- alpine 3.24: libressl-doc 4.3.1-r0 Β· custom
- arch rolling: libressl 4.4.0-1 Β· ISC AND custom:OpenSSL
- Copyright (c) 2015 Google Inc
- Copyright (c) 2018, 2022 Ingo Schwarze <schwarze@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms