Class: Linzer::MLDSA::OpenSSLKey

Inherits:
Key
  • Object
show all
Defined in:
lib/linzer/ml_dsa/openssl_key.rb

Overview

Note:

Requires OpenSSL 3.5+ with ML-DSA signature algorithms enabled. Some distributions ship OpenSSL 3.5+ with these disabled by crypto policy (see https://github.com/ruby/openssl/issues/1075), so callers should be prepared for OpenSSL::PKey::PKeyError on unsupported builds even when the OpenSSL version alone looks sufficient.

ML-DSA (FIPS 204) signing/verification backed directly by OpenSSL 3.5+, with no additional gem dependency. Supports all three parameter sets (ML-DSA-44/65/87).

Like Ed25519, ML-DSA is a "pure"/digest-less signature scheme: the RFC 9421 signature base is signed directly, with no prehashing.

Instance Attribute Summary collapse

Attributes inherited from Key

#material

Instance Method Summary collapse

Methods inherited from Key

#key_id, #private?, #public?

Constructor Details

#initialize(material, params = {}) ⇒ OpenSSLKey

Returns a new instance of OpenSSLKey.

Parameters:

  • material (OpenSSL::PKey::PKey)

    The underlying OpenSSL key

  • params (Hash) (defaults to: {})

    Additional key parameters

Options Hash (params):

  • :algorithm (String)

    Required. One of "ml-dsa-44"/"ml-dsa-65"/"ml-dsa-87"

  • :id (String)

    The key identifier (keyid)



73
74
75
76
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 73

def initialize(material, params = {})
  @algorithm = String(params.fetch(:algorithm))
  super
end

Instance Attribute Details

#algorithmString (readonly)

Returns The FIPS 204 parameter set this key was constructed for, e.g. "ml-dsa-44".

Returns:

  • (String)

    The FIPS 204 parameter set this key was constructed for, e.g. "ml-dsa-44"



66
67
68
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 66

def algorithm
  @algorithm
end

Instance Method Details

#backendSymbol

Returns :openssl -- which backend produced this key.

Returns:

  • (Symbol)

    :openssl -- which backend produced this key



113
114
115
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 113

def backend
  :openssl
end

#sign(data) ⇒ String

Signs data using the ML-DSA private key.

Parameters:

  • data (String)

    The data to sign (typically the signature base)

Returns:

  • (String)

    The FIPS 204 signature

Raises:

  • (SigningError)

    If this key does not contain private key material



96
97
98
99
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 96

def sign(data)
  validate_signing_key
  material.sign(nil, data)
end

#validate_signature_parameters(parameters) ⇒ true

Validates that the HTTP alg parameter matches this key's algorithm.

Parameters:

  • parameters (Hash)

    HTTP signature parameters

Returns:

  • (true)

    If alg is absent or matches this key

Raises:

  • (VerifyError)

    If alg selects a different algorithm



83
84
85
86
87
88
89
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 83

def validate_signature_parameters(parameters)
  supplied_algorithm = parameters["alg"] || parameters[:alg]
  return true if supplied_algorithm.nil? || supplied_algorithm == algorithm

  raise VerifyError,
    "Signature algorithm #{supplied_algorithm} does not match key algorithm #{algorithm}"
end

#verify(signature, data) ⇒ Boolean

Verifies a signature using the ML-DSA public key.

Parameters:

  • signature (String)

    The signature bytes to verify

  • data (String)

    The data that was signed

Returns:

  • (Boolean)

    true if the signature is valid, false otherwise

Raises:

  • (VerifyError)

    If this key does not contain public key material



107
108
109
110
# File 'lib/linzer/ml_dsa/openssl_key.rb', line 107

def verify(signature, data)
  validate_verify_key
  material.verify(nil, signature, data)
end