x25519.rb Latest Version Build Status Appveyor CI Status Yard Docs License: LGPL v3 Gitter Chat

An efficient public key cryptography library for Ruby providing key exchange/agreement.

This gem implements X25519 (a.k.a. Curve25519) Elliptic Curve Diffie-Hellman 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.

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.

Requirements

x25519.rb is supported on and tested against the following platforms:

  • MRI 2.2, 2.3, 2.4, 2.5

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 Diffie-Hellman 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 Diffie-Hellman with Bob's public key
alice_secret = alice_sk.diffie_hellman(bob_pk).to_bytes

# Bob can perform Diffie-Hellman 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 well-known 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 32-byte String 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 fixed-base 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 variable-base scalar multiplication, computing a shared secret between our private scalar and someone else's public key/point.

Arguments:

  • other_public_key: a X25519::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 Montgomery-u coordinate) on the elliptic curve. In the X25519 Diffie-Hellman function, these serve both as public keys and as shared secrets.

X25519::MontgomeryU.new(bytes): load existing public key

Arguments:

  • bytes: a 32-byte String value containing the public key

Example:

public_key = X25519::MontgomeryU.new(File.read("bob.pub"))

X25519::MontgomeryU#to_bytes: serialize a Montgomery-u coordinate as a String

Return Value:

Returns a String containing a byte representation of a compressed Montgomery-u coordinate:

Example:

public_key = X25519::MontgomeryU..new(...)
File.write("bob.pub", public_key.to_bytes)

X25519: module-level functionality

X25519.diffie_hellman(secret_key, public_key): shorthand String-oriented API

If you'd like to avoid the object-oriented API, you can use a simplified API which acts entirely on bytestrings.

Arguments:

  • secret_key: a 32-byte String containing a private scalar
  • public_key: a 32-byte String containing a compressed Montgomery-u coordinate

Return Value:

Returns a String containing a 32-byte compressed Montgomery-u coordinate

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/crypto-rb/x25519. This project is intended to be a safe, welcoming space for collaboration, and contributors areexpected 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 micro-architectures).
  • Efficient integer multiplication using MULX instruction.
  • Integer additions accelerated with ADCX/ADOX instructions.
  • Key generation uses a read-only table of 8 KB for X25519.

ref10: portable C implementation

  • Taken from the SUPERCOP cryptographic benchmarking suite (supercop-20171020)
  • Portable C code which should compile on any architecture

Designers

The X25519 Diffie-Hellman function was originally designed by Dan Bernstein:

https://cr.yp.to/ecdh.html

The optimized rfc7748_precomputed implementation was designed by:

  • Thomaz Oliveira, Computer Science Department, Cinvestav-IPN, Mexico.
  • Julio López, University of Campinas, Brazil.
  • Hüseyin Hisil, Yasar University, Turkey.
  • Armando Faz-Hernández, University of Campinas, Brazil.
  • Francisco Rodríguez-Henríquez, Computer Science Department, Cinvestav-IPN, Mexico.

Copyright (c) 2017-2018 Armando Faz, Tony Arcieri

This gem is available as open source under the terms of the GNU Lesser General Public License v3.0 (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.