golang/go · error
mldsa: invalid public key length
Error message
mldsa: invalid public key length
What it means
An ML-DSA public key is a fixed-size blob whose length is determined by the parameter set: 1312 bytes for ML-DSA-44, 1952 for ML-DSA-65, 2592 for ML-DSA-87. NewPublicKey44/65/87 delegate to newPublicKey, which rejects any slice that does not match the expected size for that variant. The check happens before bit-unpacking, so a truncated or wrong-variant blob is treated as malformed rather than as a verification problem.
Source
Thrown at src/crypto/internal/fips140/mldsa/mldsa.go:298
if len(pk) != pubKeySize(p) {
return nil, errInvalidPublicKeyLength
}
ρ, pk = pk[:32], pk[32:]
for r := range t1 {
// Decode four at a time from 4 * 10 bits = 5 bytes.
for i := 0; i < n; i += 4 {
b0, b1, b2, b3, b4 := pk[0], pk[1], pk[2], pk[3], pk[4]
t1[r][i+0] = uint16(b0>>0) | uint16(b1&0b0000_0011)<<8
t1[r][i+1] = uint16(b1>>2) | uint16(b2&0b0000_1111)<<6
t1[r][i+2] = uint16(b2>>4) | uint16(b3&0b0011_1111)<<4
t1[r][i+3] = uint16(b3>>6) | uint16(b4&0b1111_1111)<<2
pk = pk[5:]
}
}
return ρ, nil
}
var errInvalidPublicKeyLength = errors.New("mldsa: invalid public key length")
func NewPublicKey44(pk []byte) (*PublicKey, error) {
return newPublicKey(&PublicKey{}, pk, params44)
}
func NewPublicKey65(pk []byte) (*PublicKey, error) {
return newPublicKey(&PublicKey{}, pk, params65)
}
func NewPublicKey87(pk []byte) (*PublicKey, error) {
return newPublicKey(&PublicKey{}, pk, params87)
}
func newPublicKey(pub *PublicKey, pk []byte, p parameters) (*PublicKey, error) {
if len(pk) != pubKeySize(p) {
return nil, errInvalidPublicKeyLength
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Store the parameter set alongside the raw bytes and dispatch to the matching NewPublicKey44/65/87 constructor.
- Strip any PEM/base64/hex encoding before passing the slice; assert len(pk) equals the expected variant size first.
- If the key came from encoding x509/ssl, use the package's PublicKey parsing helpers rather than feeding DER directly.
- Round-trip test serialization (Bytes() -> NewPublicKey*) in unit tests to catch envelope bugs early.
Example fix
// before pub, err := mldsa.NewPublicKey65(pemBytes) // PEM still encoded // after block, _ := pem.Decode(pemBytes) spki, err := x509.ParsePKIXPublicKey(block.Bytes) // then convert via the mldsa helpers, or pub, err := mldsa.NewPublicKey65(raw1952Bytes)
Defensive patterns
Strategy: validation
Validate before calling
want := mldsa.PublicKeySizeForVariant(v) // 1312/1952/2592
if len(pk) != want {
return fmt.Errorf("public key must be %d bytes, got %d", want, len(pk))
} Type guard
func isMLDSA44PublicKey(pk []byte) bool { return len(pk) == 1312 } Prevention
- Always store the ML-DSA parameter set (44/65/87) next to the key bytes.
- Decode PEM/base64 once at the trust boundary and never pass encoded bytes to NewPublicKey*.
- Round-trip test Bytes()/NewPublicKey* in unit tests.
When it happens
Trigger: Calling mldsa.NewPublicKey44/65/87 with a []byte whose length is not the variant's PublicSize; e.g. feeding a 1952-byte ML-DSA-65 key into NewPublicKey44.
Common situations: Persisting/transmitting a key without recording its parameter set and reconstructing the wrong variant on load; PEM/base64/hex envelope not stripped; accidental truncation in a length-prefixed protocol; loading a DER/SPKI key without first extracting the raw ML-DSA seed.
Related errors
- mldsa: invalid seed 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/f40a1bad54343e10.
Report an issue: GitHub.