Module: X25519

Defined in:
lib/x25519.rb,
lib/x25519/scalar.rb,
lib/x25519/version.rb,
lib/x25519/montgomery_u.rb,
lib/x25519/test_vectors.rb,
lib/x25519/precomputed_not_available.rb,
ext/x25519_ref10/x25519_ref10.c,
ext/x25519_precomputed/x25519_precomputed.c

Overview

The X25519 elliptic curve Diffie-Hellman algorithm

Defined Under Namespace

Modules: Provider, TestVectors Classes: MontgomeryU, Scalar

Constant Summary collapse

KEY_SIZE =

Size of an X25519 key (public or private) in bytes

32
InvalidKeyError =

Raised when we detect a degenerate (i.e. all-zero) public key

Class.new(StandardError)
SelfTestFailure =

Raised when the built-in self-test fails

Class.new(StandardError)
VERSION =
"1.0.10"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.providerObject

Obtain the backend provider module



34
35
36
# File 'lib/x25519.rb', line 34

def provider
  @provider
end

Class Method Details

.calculate_public_key(scalar_bytes) ⇒ String

Raw fixed-base scalar multiplication function that acts directly on bytestrings. Calculates the coordinate of the elliptic curve point that represents the public key for a given scalar.

Parameters:

  • scalar_bytes (String)

    a serialized private scalar

Returns:

  • (String)

    compressed Montgomery-u coordinate of the resulting point



52
53
54
55
# File 'lib/x25519.rb', line 52

def calculate_public_key(scalar_bytes)
  validate_key_bytes(scalar_bytes)
  provider.scalarmult_base(scalar_bytes)
end

.diffie_hellman(scalar_bytes, montgomery_u_bytes) ⇒ String

Raw Diffie-Hellman function that acts directly on bytestrings. An alternative to the object-oriented API

Parameters:

  • scalar_bytes (String)

    a serialized private scalar

  • montgomery_u_bytes (String)

    a point we wish to multiply by the scalar

Returns:

  • (String)

    resulting point, serialized as bytes

Raises:



64
65
66
67
68
69
70
71
72
73
# File 'lib/x25519.rb', line 64

def diffie_hellman(scalar_bytes, montgomery_u_bytes)
  validate_key_bytes(scalar_bytes)
  validate_key_bytes(montgomery_u_bytes)

  # The point located at a Montgomery-u coordinate of zero always returns
  # the point at zero regardless of which scalar it's multiplied with
  raise InvalidKeyError, "degenerate public key" if montgomery_u_bytes == ("\0" * KEY_SIZE)

  provider.scalarmult(scalar_bytes, montgomery_u_bytes)
end

.self_testObject

Perform a self-test to ensure the selected provider is working



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/x25519.rb', line 84

def self_test
  X25519::TestVectors::VARIABLE_BASE.each do |v|
    shared_secret = provider.scalarmult([v.scalar].pack("H*"), [v.input_coord].pack("H*"))
    raise SelfTestFailure, "self test failed!" unless shared_secret.unpack1("H*") == v.output_coord
  end

  X25519::TestVectors::FIXED_BASE.each do |v|
    public_key = provider.scalarmult_base([v.scalar].pack("H*"))
    raise SelfTestFailure, "self test failed!" unless public_key.unpack1("H*") == v.output_coord
  end

  true
end

.validate_key_bytes(key_bytes) ⇒ Object

Ensure a serialized key meets the requirements

Raises:

  • (TypeError)


76
77
78
79
80
81
# File 'lib/x25519.rb', line 76

def validate_key_bytes(key_bytes)
  raise TypeError, "expected String, got #{key_bytes.class}" unless key_bytes.is_a?(String)
  return true if key_bytes.bytesize == KEY_SIZE

  raise ArgumentError, "expected #{KEY_SIZE}-byte String, got #{key_bytes.bytesize}"
end