golang/go · error
mldsa: invalid seed length
Error message
mldsa: invalid seed length
What it means
ML-DSA (FIPS 204) key generation derives the full keypair deterministically from a 32-byte seed ξ. The constructors NewPrivateKey44/65/87 validate that the supplied seed slice is exactly 32 bytes before invoking the (expensive) key-derivation routine, refusing to run on malformed input. A wrong length therefore never reaches FIPS self-tests and is reported as a plain input error rather than a cryptographic failure.
Source
Thrown at src/crypto/internal/fips140/mldsa/mldsa.go:143
fips140.RecordApproved()
var seed [32]byte
drbg.Read(seed[:])
priv := newPrivateKey(&seed, params65)
fipsPCT(priv)
return priv
}
func GenerateKey87() *PrivateKey {
fipsSelfTest()
fips140.RecordApproved()
var seed [32]byte
drbg.Read(seed[:])
priv := newPrivateKey(&seed, params87)
fipsPCT(priv)
return priv
}
var errInvalidSeedLength = errors.New("mldsa: invalid seed length")
func NewPrivateKey44(seed []byte) (*PrivateKey, error) {
fipsSelfTest()
fips140.RecordApproved()
if len(seed) != 32 {
return nil, errInvalidSeedLength
}
return newPrivateKey((*[32]byte)(seed), params44), nil
}
func NewPrivateKey65(seed []byte) (*PrivateKey, error) {
fipsSelfTest()
fips140.RecordApproved()
if len(seed) != 32 {
return nil, errInvalidSeedLength
}
return newPrivateKey((*[32]byte)(seed), params65), nil
}View on GitHub (pinned to b6b368adc5)
Solutions
- Allocate a [32]byte and fill it with crypto/rand.Read(seed[:]) before calling NewPrivateKey*.
- If the seed arrives hex/base64-encoded, decode it first (hex.DecodeString / base64.StdEncoding.DecodeString) and assert the decoded length is 32.
- If you do not need deterministic key derivation from a seed, call GenerateKey44/65/87 instead, which internally draws the 32 bytes from the FIPS DRBG.
- Add a length guard at the trust boundary (API handler, deserializer) so malformed seeds are rejected before reaching the crypto layer.
Example fix
// before
seed := []byte("my-fixed-passphrase-seed") // wrong length
pk, err := mldsa.NewPrivateKey44(seed)
// after
var seed [32]byte
if _, err := io.ReadFull(rand.Reader, seed[:]); err != nil { return err }
pk, err := mldsa.NewPrivateKey44(seed[:]) Defensive patterns
Strategy: validation
Validate before calling
if len(seed) != 32 {
return fmt.Errorf("mldsa seed must be 32 bytes, got %d", len(seed))
}
pk, err := mldsa.NewPrivateKey44(seed) Type guard
// seed must be exactly 32 bytes; represent it as an array to make the
// length a compile-time property.
func validateSeed(seed *[32]byte) bool { return seed != nil } Prevention
- Type seeds as [32]byte (not []byte) so the length is enforced at compile time.
- Decode hex/base64 at the API boundary and assert decoded length before any crypto call.
- Centralize seed generation in one helper that always uses crypto/rand with a [32]byte buffer.
When it happens
Trigger: Calling mldsa.NewPrivateKey44(seed), NewPrivateKey65(seed), or NewPrivateKey87(seed) with a []byte whose length is not 32 (e.g. 16, 48, 64). The len(seed) != 32 branch at the top of the constructor returns errInvalidSeedLength.
Common situations: Passing a hex- or base64-encoded string instead of raw bytes (length 64/44 instead of 32); reading a short/truncated byte slice from a config file or env var; confusing ML-DSA's 32-byte seed with ML-KEM's 64-byte d||z seed; using crypto/rand with a wrong-sized buffer.
Related errors
- mldsa: invalid public key length
- mldsa: invalid signature length
- mldsa: context too long
- mldsa: invalid message hash length
- mldsa: invalid semi-expanded private key size
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/85cf464910524e78.
Report an issue: GitHub.