x25519.rb
An efficient public key cryptography library for Ruby providing key exchange/agreement.
This gem implements X25519 (a.k.a. Curve25519) Elliptic Curve DiffieHellman function as described in RFC7748 as a C extension using the high performance rfc7748_precomputed implementation based on the paper How to (pre)compute a ladder (with fallback to the ref10 C implementation).
X25519 is one of two notable algorithms implemented atop the Curve25519 elliptic curve. The ed25519 gem is a related project of this one, and implements the Ed25519 signature scheme on the twisted Edwards form of Curve25519.
Is it any good?
What is it useful for?
X25519 is a key exchange/agreement algorithm generally used as a lowlevel building block in cryptographic protocols.
Can I use X25519 to encrypt things?
Please use RbNaCl::Box if you would like a highlevel construction which uses X25519 for publickey encryption. Otherwise, the X25519 algorithm is not directly useful for encryption without a higherlevel encryption protocol built on top of it.
Requirements
x25519.rb is supported on and tested against the following platforms:
 MRI 2.5, 2.6, 2.7, 3.0
Installation
Add this line to your application's Gemfile:
gem "x25519"
And then execute:
$ bundle
Or install it yourself as:
$ gem install x25519
Usage
The example below shows how to perform a full DiffieHellman key exchange:
require "x25519"
# Alice generates random scalar (private key)
alice_sk = X25519::Scalar.generate
# Alice obtains public key for her private key/scalar
alice_pk = alice_sk.public_key
# Bob generates random scalar (private key)
# Ostensibly this would be on a different computer somewhere
bob_sk = X25519::Scalar.generate
bob_pk = bob_sk.public_key
# Alice can perform DiffieHellman with Bob's public key
alice_secret = alice_sk.diffie_hellman(bob_pk).to_bytes
# Bob can perform DiffieHellman with Alice's public key
bob_secret = bob_sk.diffie_hellman(alice_pk).to_bytes
# The resulting secrets should be the same
alice_secret == bob_secret # true
X25519::Scalar: private keys
The X25519::Scalar
class represents secret integers used as X25519 private
keys. These secret integers are multiplied by a wellknown base point to
obtain X25519 public keys (X25519::MontgomeryU
).
X25519::Scalar.generate()
: make a random private key
Generate a random private scalar (using SecureRandom
)
Example:
secret_key = X25519::Scalar.generate
X25519::Scalar.new(bytes)
: load existing private key

bytes
: a 32byteString
value containing the private key
Example:
secret_key = X25519::Scalar.new(File.read("alice.key"))
X25519::Scalar#public_key()
: obtain public key for this scalar
NOTE: The #multiply_base
method is an alias of this one.
Performs fixedbase scalar multiplication (i.e. calculates public key)
Return Value:
Returns a X25519::MontgomeryU
object which represents the public key for this private key/scalar.
Example:
secret_key = X25519::Scalar.generate
public_key = secret_key.public_key
X25519::Scalar#diffie_hellman(other_public_key)
: obtain public key for this scalar
NOTE: The #multiply
method is an alias of this one.
Performs variablebase scalar multiplication, computing a shared secret between our private scalar and someone else's public key/point.
Arguments:

other_public_key
: aX25519::MontgomeryU
object containing the public key with which we'd like to compute a shared secret.
Return Value:
Returns a X25519::MontgomeryU
object which represents the shared secret.
Example:
secret_key = X25519::Scalar.generate
public_key = X25519::MontgomeryU.new(File.read("bob.pub"))
# Returns an X25519::MontgomeryU
shared_secret = secret_key.multiply(public_key)
# Obtain the shared secret as a serialized byte representation
shared_secret_bytes = shared_secret.to_bytes
X25519::Scalar#to_bytes
: serialize a scalar as a String
Return Value:
Returns a String
containing a byte representation of this scalar:
Example:
secret_key = X25519::Scalar.new(...)
File.write("alice.key", secret_key.to_bytes)
X25519::MontgomeryU: public keys and shared secrets
The X25519::MontgomeryU
class represents a coordinate (specifically a
Montgomeryu coordinate) on the elliptic curve. In the X25519 DiffieHellman
function, these serve both as public keys and as shared secrets.
X25519::MontgomeryU.new(bytes)
: load existing public key
Arguments:

bytes
: a 32byteString
value containing the public key
Example:
public_key = X25519::MontgomeryU.new(File.read("bob.pub"))
X25519::MontgomeryU#to_bytes
: serialize a Montgomeryu coordinate as a String
Return Value:
Returns a String
containing a byte representation of a compressed Montgomeryu coordinate:
Example:
public_key = X25519::MontgomeryU..new(...)
File.write("bob.pub", public_key.to_bytes)
X25519: modulelevel functionality
X25519.diffie_hellman(secret_key, public_key)
: shorthand String
oriented API
If you'd like to avoid the objectoriented API, you can use a simplified API which acts entirely on bytestrings.
Arguments:

secret_key
: a 32byteString
containing a private scalar 
public_key
: a 32byteString
containing a compressed Montgomeryu coordinate
Return Value:
Returns a String
containing a 32byte compressed Montgomeryu coordinate
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/RubyCrypto/x25519. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Implementation Details
This gem contains two implementations of X25519: an optimized assembly implementation and a portable C implementation. Implementations are selected based on available CPU features.
rfc7748_precomputed: optimized assembly implementation
 Prime field arithmetic is optimized for the 4th and 6th generation of Intel Core processors (Haswell and Skylake microarchitectures).
 Efficient integer multiplication using MULX instruction.
 Integer additions accelerated with ADCX/ADOX instructions.
 Key generation uses a readonly table of 8 KB for X25519.
ref10: portable C implementation
 Taken from the SUPERCOP cryptographic benchmarking suite (supercop20171020)
 Portable C code which should compile on any architecture
Designers
The X25519 DiffieHellman function was originally designed by Dan Bernstein:
The optimized rfc7748_precomputed implementation was designed by:
 Thomaz Oliveira, Computer Science Department, CinvestavIPN, Mexico.
 Julio López, University of Campinas, Brazil.
 Hüseyin Hisil, Yasar University, Turkey.
 Armando FazHernández, University of Campinas, Brazil.
 Francisco RodríguezHenríquez, Computer Science Department, CinvestavIPN, Mexico.
License
Copyright (c) 20172018 Armando Faz Copyright (c) 20172021 Tony Arcieri
This gem is available as open source under the terms of the BSD3 Clause License (LICENSE)
Code of Conduct
Everyone interacting in the x25519.rb project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.