x25519.rb Latest Version Yard Docs License: BSD 3-Clause Build Status

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.

Is it any good?

Yes.

What is it useful for?

X25519 is a key exchange/agreement algorithm generally used as a low-level building block in cryptographic protocols.

Can I use X25519 to encrypt things?

Please use RbNaCl::Box if you would like a high-level construction which uses X25519 for public-key encryption. Otherwise, the X25519 algorithm is not directly useful for encryption without a higher-level 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 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/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 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.

License

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

This gem is available as open source under the terms of the BSD-3 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.