lib/x25519.rb in x25519-1.0.2 vs lib/x25519.rb in x25519-1.0.3
- old
+ new
@@ -17,10 +17,13 @@
module_function
# Size of an X25519 key (public or private) in bytes
KEY_SIZE = 32
+ # Raised when we detect a degenerate (i.e. all-zero) public key
+ InvalidKeyError = Class.new(StandardError)
+
# Raised when the built-in self-test fails
SelfTestFailure = Class.new(StandardError)
class << self
# Obtain the backend provider module
@@ -33,20 +36,37 @@
# X25519::Precomputed requires a 4th generation Intel Core CPU or newer,
# so only enable it if we detect we're on a supported platform. Otherwise,
# fall back to the ref10 portable C implementation.
self.provider = X25519::Provider::Precomputed if X25519::Provider::Precomputed.available?
+ # 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.
+ #
+ # @param scalar_bytes [String] a serialized private scalar
+ #
+ # @return [String] compressed Montgomery-u coordinate of the resulting point
+ def calculate_public_key(scalar_bytes)
+ validate_key_bytes(scalar_bytes)
+ provider.scalarmult_base(scalar_bytes)
+ end
+
# Raw Diffie-Hellman function that acts directly on bytestrings. An
# alternative to the object-oriented API
#
# @param scalar_bytes [String] a serialized private scalar
# @param montgomery_u_bytes [String] a point we wish to multiply by the scalar
#
# @return [String] resulting point, serialized as bytes
def diffie_hellman(scalar_bytes, montgomery_u_bytes)
validate_key_bytes(scalar_bytes)
validate_key_bytes(montgomery_u_bytes)
- X25519.provider.scalarmult(scalar_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
# Ensure a serialized key meets the requirements
def validate_key_bytes(key_bytes)
raise TypeError, "expected String, got #{key_bytes.class}" unless key_bytes.is_a?(String)