{"record":{"id":"76db0f2cbc5afdd2","repo":"golang/go","slug":"mldsa-invalid-semi-expanded-private-key-size","errorCode":null,"errorMessage":"mldsa: invalid semi-expanded private key size","messagePattern":"mldsa: invalid semi-expanded private key size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mldsa/semiexpanded.go","lineNumber":48,"sourceCode":"}\n\n// TestingOnlyNewPrivateKeyFromSemiExpanded creates a PrivateKey from a\n// semi-expanded private key encoding, for testing purposes. It rejects\n// inconsistent keys.\n//\n// [PrivateKey.Bytes] must NOT be called on the resulting key, as it will\n// produce a random value.\nfunc TestingOnlyNewPrivateKeyFromSemiExpanded(sk []byte) (*PrivateKey, error) {\n\tvar p parameters\n\tswitch len(sk) {\n\tcase semiExpandedPrivKeySize(params44):\n\t\tp = params44\n\tcase semiExpandedPrivKeySize(params65):\n\t\tp = params65\n\tcase semiExpandedPrivKeySize(params87):\n\t\tp = params87\n\tdefault:\n\t\treturn nil, errors.New(\"mldsa: invalid semi-expanded private key size\")\n\t}\n\tk, l := p.k, p.l\n\n\tρ, K, tr, s1, s2, t0, err := skDecode(sk, p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpriv := &PrivateKey{pub: PublicKey{p: p}}\n\tpriv.k = K\n\tpriv.pub.tr = tr\n\tA := priv.a[:k*l]\n\tcomputeMatrixA(A, ρ[:], p)\n\tfor r := range l {\n\t\tpriv.s1[r] = ntt(s1[r])\n\t}\n\tfor r := range k {\n\t\tpriv.s2[r] = ntt(s2[r])","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mldsa/semiexpanded.go#L30-L66","documentation":"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.","triggerScenarios":"Calling TestingOnlyNewPrivateKeyFromSemiExpanded(sk) with a slice whose length is not semiExpandedPrivKeySize(params44/65/87).","commonSituations":"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.","solutions":["Ensure the input is exactly the semi-expanded form produced by TestingOnlyPrivateKeySemiExpandedBytes for the same variant.","Round-trip the bytes through TestingOnlyPrivateKeySemiExpandedBytes in the test harness to confirm sizes line up.","Do not use this API outside ACVP testing; for production use NewPrivateKey*/GenerateKey*."],"exampleFix":"// before\npriv, err := mldsa.TestingOnlyNewPrivateKeyFromSemiExpanded(fullNistBlob)\n\n// after\nsemi := mldsa.TestingOnlyPrivateKeySemiExpandedBytes(referencePriv)\npriv, err := mldsa.TestingOnlyNewPrivateKeyFromSemiExpanded(semi)","handlingStrategy":"validation","validationCode":"ok := len(sk) == semiExpandedSize44 ||\n    len(sk) == semiExpandedSize65 ||\n    len(sk) == semiExpandedSize87\nif !ok { return ErrBadSemiExpandedSize }","typeGuard":"func isSemiExpandedSize(n int) bool {\n    return n == semiExpandedSize44 || n == semiExpandedSize65 || n == semiExpandedSize87\n}","tryCatchPattern":null,"preventionTips":["Use this API only for ACVP testing, never in production.","Round-trip bytes through TestingOnlyPrivateKeySemiExpandedBytes to confirm sizes.","Prefer NewPrivateKey*/GenerateKey* for real key handling."],"tags":["crypto","mldsa","fips","testing","input-length"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}