golang/go · error

mldsa: unavailable in FIPS 140-3 Go Cryptographic Module v1.

Error message

mldsa: unavailable in FIPS 140-3 Go Cryptographic Module v1.0.0

What it means

Returned by every top-level ML-DSA function in the stub file mldsa_fips140v1.0.go, which is compiled when building against the FIPS 140-3 Go Cryptographic Module v1.0.0. ML-DSA (NIST FIPS 204 post-quantum lattice signature) was not included in FIPS module v1.0, so the entire API is stubbed to return errUnavailable and methods are unreachable because PrivateKey/PublicKey are empty structs that cannot be constructed.

Source

Thrown at src/crypto/mldsa/mldsa_fips140v1.0.go:20

// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build fips140v1.0

package mldsa

import (
	"crypto"
	"errors"
	"io"
)

// This file provides stub implementations of the ML-DSA API for building
// against the FIPS 140-3 Go Cryptographic Module v1.0.0, which does not include
// ML-DSA. Top-level functions return an error, and methods are unreachable
// since there is no way to construct a valid PublicKey or PrivateKey.

var errUnavailable = errors.New("mldsa: unavailable in FIPS 140-3 Go Cryptographic Module v1.0.0")

// PrivateKey is an in-memory ML-DSA private key. It implements [crypto.Signer]
// and the informal extended [crypto.PrivateKey] interface.
//
// A PrivateKey is safe for concurrent use.
type PrivateKey struct{}

// GenerateKey generates a new random ML-DSA private key.
func GenerateKey(params Parameters) (*PrivateKey, error) {
	return nil, errUnavailable
}

// NewPrivateKey decodes an ML-DSA private key from the given seed.
//
// The seed must be exactly [PrivateKeySize] bytes long.
func NewPrivateKey(params Parameters, seed []byte) (*PrivateKey, error) {
	return nil, errUnavailable
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Build/run against FIPS 140-3 Go Cryptographic Module v1.26.0 or later, which includes ML-DSA (the mldsa_fips140v1.26.go file with real GenerateKey44/65/87 is selected).
  2. If you cannot upgrade the module, remove or feature-gate the ML-DSA code path so it is not called in v1.0 builds.
  3. Detect errUnavailable at startup and fall back to a classical signature (Ed25519/ECDSA) when ML-DSA is unavailable, if your protocol allows it.
  4. Pin the FIPS module version explicitly via GOFIPS / build tags and document the dependency in release notes.

Example fix

// before
priv, err := mldsa.GenerateKey(mldsa.MLDSA65()) // -> errUnavailable under v1.0
// after
priv, err := mldsa.GenerateKey(mldsa.MLDSA65())
if errors.Is(err, errUnavailable) { priv, err = ed25519.GenerateKey(rand.Reader) }
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect at startup whether ML-DSA is available in this build:
if _, err := mldsa.GenerateKey(mldsa.MLDSA44()); errors.Is(err, errUnavailable) {
    log.Println("ML-DSA unavailable; falling back to classical signatures")
}

Try / catch

priv, err := mldsa.GenerateKey(mldsa.MLDSA65())
if errors.Is(err, errUnavailable) {
    // FIPS module v1.0 in use; fall back to a classical signature
    priv, err = ed25519.GenerateKey(rand.Reader)
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Calling mldsa.GenerateKey (or any other top-level ML-DSA function: Sign, Verify, etc.) in a binary built against FIPS module v1.0 — i.e. the GOFIPS env var points at the v1.0 module, or the gofips build tag selects v1.0. There is no code path that returns a valid key, so all callers fail.

Common situations: Post-quantum pilot code deployed into a FIPS-only environment pinned to module v1.0; CI builds with the v1.0 module tag while developers expected the v1.26 API; library code that conditionally uses ML-DSA but the build resolved to the v1.0 stub file.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/dc28e3601771f22d. Report an issue: GitHub.