golang/go · error
mldsa: zero public key
Error message
mldsa: zero public key
What it means
Returned by Verify when pk is non-nil but the inner mldsa.PublicKey value pk.p is the zero value — i.e. the wrapper struct exists but was never populated with real key material. This catches a half-initialized PublicKey that would otherwise fail deep inside mldsa.Verify with a less actionable error. The check is pk.p == (mldsa.PublicKey{}).
Source
Thrown at src/crypto/mldsa/mldsa_fips140v1.26.go:220
case "ML-DSA-44":
return MLDSA44()
case "ML-DSA-65":
return MLDSA65()
case "ML-DSA-87":
return MLDSA87()
default:
panic("mldsa: invalid parameters in public key")
}
}
// Verify reports whether signature is a valid signature of message by pk.
// If opts is nil, it's equivalent to the zero value of Options.
func Verify(pk *PublicKey, message []byte, signature []byte, opts *Options) error {
if pk == nil {
return errors.New("mldsa: nil public key")
}
if pk.p == (mldsa.PublicKey{}) {
return errors.New("mldsa: zero public key")
}
if opts == nil {
opts = &Options{}
}
return mldsa.Verify(&pk.p, message, signature, opts.Context)
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Build the public key through the documented constructor/decode API so pk.p is populated.
- After loading, sanity-check: if pk == nil || pk.Bytes() is empty, abort.
- Propagate decode errors rather than defaulting to an empty PublicKey.
Example fix
// before
pk := &mldsa.PublicKey{} // inner p is zero value
err := mldsa.Verify(pk, msg, sig, nil) // "mldsa: zero public key"
// after
pk, err := mldsa.NewPublicKeyFromBytes(raw)
if err != nil { return err }
err = mldsa.Verify(pk, msg, sig, nil) Defensive patterns
Strategy: validation
Validate before calling
if pk == nil || len(pk.Bytes()) == 0 {
return errors.New("public key not initialized")
}
return mldsa.Verify(pk, msg, sig, opts) Type guard
func (pk *PublicKey) isInitialized() bool {
return pk != nil && len(pk.Bytes()) > 0
} Try / catch
if err := mldsa.Verify(pk, msg, sig, opts); err != nil {
if strings.Contains(err.Error(), "zero public key") {
pk, err = reloadPublicKey()
if err != nil { return err }
err = mldsa.Verify(pk, msg, sig, opts)
}
return err
} Prevention
- Always construct PublicKey via the decode/constructor API.
- Propagate decode errors instead of defaulting to an empty struct.
- Add a byte-length assertion after loading public keys.
When it happens
Trigger: Constructing &mldsa.PublicKey{} directly without running through NewPublicKey / Decode. A decode function that returned a non-nil pointer but left p zero on partial failure.
Common situations: Copying a PublicKey by value into a fresh struct and forgetting to populate the inner field. JSON/gob deserialization that allocates the wrapper but does not set the internal field. A lookup cache that stores an empty PublicKey sentinel.
Related errors
- mldsa: zero private key
- mldsa: nil public key
- mldsa: invalid SignerOpts
- mlkemtest: Encapsulate768: random must be 32 bytes
- crypto/mlkem/mlkemtest: use of derandomized encapsulation is
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/8835af12b5bf653e.
Report an issue: GitHub.