golang/go · error

mldsa: invalid semi-expanded private key size

Error message

mldsa: invalid semi-expanded private key size

What it means

TestingOnlyNewPrivateKeyFromSemiExpanded accepts the NIST 'semi-expanded' private-key form (ρ || K || tr || s1 || s2 || t0) and infers the parameter set purely from the total byte length. If the slice matches none of the three expected sizes it returns errInvalidSeedLength's sibling 'invalid semi-expanded private key size'. This API exists for ACVP (FIPS CAVP) conformance testing only and is not part of the public surface.

Source

Thrown at src/crypto/internal/fips140/mldsa/semiexpanded.go:48

}

// TestingOnlyNewPrivateKeyFromSemiExpanded creates a PrivateKey from a
// semi-expanded private key encoding, for testing purposes. It rejects
// inconsistent keys.
//
// [PrivateKey.Bytes] must NOT be called on the resulting key, as it will
// produce a random value.
func TestingOnlyNewPrivateKeyFromSemiExpanded(sk []byte) (*PrivateKey, error) {
	var p parameters
	switch len(sk) {
	case semiExpandedPrivKeySize(params44):
		p = params44
	case semiExpandedPrivKeySize(params65):
		p = params65
	case semiExpandedPrivKeySize(params87):
		p = params87
	default:
		return nil, errors.New("mldsa: invalid semi-expanded private key size")
	}
	k, l := p.k, p.l

	ρ, K, tr, s1, s2, t0, err := skDecode(sk, p)
	if err != nil {
		return nil, err
	}

	priv := &PrivateKey{pub: PublicKey{p: p}}
	priv.k = K
	priv.pub.tr = tr
	A := priv.a[:k*l]
	computeMatrixA(A, ρ[:], p)
	for r := range l {
		priv.s1[r] = ntt(s1[r])
	}
	for r := range k {
		priv.s2[r] = ntt(s2[r])

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the input is exactly the semi-expanded form produced by TestingOnlyPrivateKeySemiExpandedBytes for the same variant.
  2. Round-trip the bytes through TestingOnlyPrivateKeySemiExpandedBytes in the test harness to confirm sizes line up.
  3. Do not use this API outside ACVP testing; for production use NewPrivateKey*/GenerateKey*.

Example fix

// before
priv, err := mldsa.TestingOnlyNewPrivateKeyFromSemiExpanded(fullNistBlob)

// after
semi := mldsa.TestingOnlyPrivateKeySemiExpandedBytes(referencePriv)
priv, err := mldsa.TestingOnlyNewPrivateKeyFromSemiExpanded(semi)
Defensive patterns

Strategy: validation

Validate before calling

ok := len(sk) == semiExpandedSize44 ||
    len(sk) == semiExpandedSize65 ||
    len(sk) == semiExpandedSize87
if !ok { return ErrBadSemiExpandedSize }

Type guard

func isSemiExpandedSize(n int) bool {
    return n == semiExpandedSize44 || n == semiExpandedSize65 || n == semiExpandedSize87
}

Prevention

When it happens

Trigger: Calling TestingOnlyNewPrivateKeyFromSemiExpanded(sk) with a slice whose length is not semiExpandedPrivKeySize(params44/65/87).

Common situations: Feeding the expanded (full) NIST key instead of the semi-expanded form; truncating/over-reading the byte buffer; using this test helper with production data.

Related errors


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