Rust-X25519 dalek: x25519-dalek — Pure Rust implementation of X25519 key exchange


A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, with curve operations provided by curve25519-dalek.

This crate provides two levels of API: a bare byte-oriented x25519 function which matches the function specified in RFC7748, as well as a higher-level Rust API for static and ephemeral Diffie-Hellman.


Alice and Bob are two adorable kittens who have lost their mittens, and they wish to be able to send secret messages to each other to coordinate finding them, otherwise—if their caretaker cat finds out—they will surely be called naughty kittens and be given no pie!

But the two kittens are quite clever. Even though their paws are still too big and the rest of them is 90% fuzziness, these clever kittens have been studying up on modern public key cryptography and have learned a nifty trick called elliptic curve Diffie-Hellman key exchange. With the right incantations, the kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie!

First, Alice uses EphemeralSecret::new() and then PublicKey::from() to produce her secret and public keys:

extern crate rand_os;
extern crate x25519_dalek;

use rand_os::OsRng;

use x25519_dalek::EphemeralSecret;
use x25519_dalek::PublicKey;

let mut alice_csprng = OsRng::new().unwrap();
let     alice_secret = EphemeralSecret::new(&mut alice_csprng);
let     alice_public = PublicKey::from(&alice_secret);

Bob does the same:

let mut bob_csprng = OsRng::new().unwrap();
let     bob_secret = EphemeralSecret::new(&mut bob_csprng);
let     bob_public = PublicKey::from(&bob_secret);

Alice meows across the room, telling alice_public to Bob, and Bob loudly meows bob_public back to Alice. Alice now computes her shared secret with Bob by doing:

let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);

Similarly, Bob computes a shared secret by doing:

let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);

These secrets are the same:

assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());

Voilá! Alice and Bob can now use their shared secret to encrypt their meows, for example, by using it to generate a key and nonce for an authenticated-encryption cipher.

This example used the ephemeral DH API, which ensures that secret keys cannot be reused; Alice and Bob could instead use the static DH API and load a long-term secret key.


To install, add the following to your project's Cargo.toml:

version = "0.6"


Documentation is available here.


This code matches the RFC7748 test vectors. The elliptic curve operations are provided by curve25519-dalek, which makes a best-effort attempt to prevent software side-channels.

"Secret Messages" cover image and zine copyright © Amy Wibowo (@sailorhg)


  • Documentation and example on bare bytes API
    Documentation and example on bare bytes API

    Jan 23, 2019

    I checked out the bare-bytes API for use with FFI. The API is easy enough for people who knows a bit about Elliptic Curves and Diffie-Hellman, but can be pretty confusing for people with limited knowledge. Without any modification to the code itself, I suggest to add a usage example to the x25519() function in the docs. I can write the example, test it and make a PR, but I just wanted to know your input about it before doing it!

  • Added doc example for x25519()
    Added doc example for x25519()

    Jan 25, 2019

    Adding documentation example for bare byte API, as per

  • Add .to_bytes() to PublicKey, SharedSecret
    Add .to_bytes() to PublicKey, SharedSecret

    Jun 5, 2019

    Added so that x25519_dalek::PublicKey has the same as_bytes/to_bytes fns as ed25519_dalek::PublicKey

    Also added .to_bytes() to SharedSecret for consistency.

  • Add a mode to avoid degenerate points
    Add a mode to avoid degenerate points

    Nov 13, 2019


  • Feedback/Suggestion

    Apr 15, 2020


    I've been implementing Noise with x25519-dalek and I have a few suggestions:

    • for ephemeral keys, the diffie-hellman operation consumes the private key, which doesn't work if I need to use the ephemeral keys in more than one Diffie-Hellman operation (common with Noise)
    • a public_key(&self) operation on private keys would be really handy
    • a try_from<&[u8]> operation for private and public keys would be really handy

    (happy to take a stab at a PR if you want me to)

  • 'Secret' trait for unified DH
    'Secret' trait for unified DH

    May 24, 2020

    Introduced a Secret trait to encapsulate Diffie-Hellman functionality of both StaticSecret and EphemeralSecret.

    Any overlaying logic would not care if it calculates DH on a static or ephemeral secret. This would enable to build generic interfaces using the trait as a DH mediator.

    For example X3DH uses static and ephemeral keys during it's agreement calculation:

  • use production rand 0.5 release
    use production rand 0.5 release

    May 23, 2018

    0.5 is finally out of prerelease purgatory ?

  • Unable to build docs with nightly flag
    Unable to build docs with nightly flag

    May 28, 2019

    When building with no-default-feautures, u64_backend std and nightly

        Checking x25519-dalek v0.5.2
    error[E0432]: unresolved import `packed_simd`
      --> /Users/dignifiedquire/.cargo/registry/src/
    43 | use packed_simd::{i32x8, u32x8, u64x4, IntoBits};
       |     ^^^^^^^^^^^ maybe a missing `extern crate packed_simd;`?
  • Upgrade rand dependency
    Upgrade rand dependency

    Aug 10, 2019

  • Types with Drop to hold the secret keys (and others if needed)
    Types with Drop to hold the secret keys (and others if needed)

    Jun 6, 2018

    libsodium provides a mem-zeroing functionality which gets called from the rust versions (e.g. rust_sodium) for at-least all the secret keys which are user-defined types with Drop. There is no such management in dalek. Just wandering on what the opinions are on this:

    • It is important and we need it and dalek is ready to provide it
    • It is important but the user is expected to do the wrapping but dalek wouldn't see this as its goal
    • It's not needed (if so any reasons would be good to know)
    enhancement good first issue help wanted 
  • subtl dependency broken again
    subtl dependency broken again

    Jan 10, 2019

    subtle 0.7 was yanked, but x25519-dalek requires exactly curve25519-dalek 0.19, which depends on exactly subtle 0.7

        Updating git repository ``
        Updating index
    error: failed to select a version for the requirement `subtle = "^0.7"`
      candidate versions found which didn't match: 2.0.0, 1.0.0
      location searched: index
    required by package `curve25519-dalek v0.19.0`
        ... which is depended on by `x25519-dalek v0.3.0`
        ... which is depended on by `carrier v0.8.0 (/home/aep/proj/devguard/carrier2)`
  • Serializing EphemeralPublic
    Serializing EphemeralPublic

    Jan 22, 2019

    We need to serialize EphemeralPublic (over here) to an array of bytes so we can share it between network participants.

    I see that the underlying MontgomeryPoint has a to_bytes() function, but this is inaccessible due to the fact that EphemeralPublic doesn't expose any such function, and the underlying MontgomeryPoint in the EphemeralPublic tuple is private outside of its crate.

    Is there some other way to access a to_bytes() function for the EphemeralPublic struct that has the same effect?

    This was easier in older versions of x25519-dalek, but the older subtle dependency being yanked (as per #19) prevents us from continuing to use the older version of the package.