{"record":{"id":"f40a1bad54343e10","repo":"golang/go","slug":"mldsa-invalid-public-key-length","errorCode":null,"errorMessage":"mldsa: invalid public key length","messagePattern":"mldsa: invalid public key length","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mldsa/mldsa.go","lineNumber":298,"sourceCode":"\tif len(pk) != pubKeySize(p) {\n\t\treturn nil, errInvalidPublicKeyLength\n\t}\n\tρ, pk = pk[:32], pk[32:]\n\tfor r := range t1 {\n\t\t// Decode four at a time from 4 * 10 bits = 5 bytes.\n\t\tfor i := 0; i < n; i += 4 {\n\t\t\tb0, b1, b2, b3, b4 := pk[0], pk[1], pk[2], pk[3], pk[4]\n\t\t\tt1[r][i+0] = uint16(b0>>0) | uint16(b1&0b0000_0011)<<8\n\t\t\tt1[r][i+1] = uint16(b1>>2) | uint16(b2&0b0000_1111)<<6\n\t\t\tt1[r][i+2] = uint16(b2>>4) | uint16(b3&0b0011_1111)<<4\n\t\t\tt1[r][i+3] = uint16(b3>>6) | uint16(b4&0b1111_1111)<<2\n\t\t\tpk = pk[5:]\n\t\t}\n\t}\n\treturn ρ, nil\n}\n\nvar errInvalidPublicKeyLength = errors.New(\"mldsa: invalid public key length\")\n\nfunc NewPublicKey44(pk []byte) (*PublicKey, error) {\n\treturn newPublicKey(&PublicKey{}, pk, params44)\n}\n\nfunc NewPublicKey65(pk []byte) (*PublicKey, error) {\n\treturn newPublicKey(&PublicKey{}, pk, params65)\n}\n\nfunc NewPublicKey87(pk []byte) (*PublicKey, error) {\n\treturn newPublicKey(&PublicKey{}, pk, params87)\n}\n\nfunc newPublicKey(pub *PublicKey, pk []byte, p parameters) (*PublicKey, error) {\n\tif len(pk) != pubKeySize(p) {\n\t\treturn nil, errInvalidPublicKeyLength\n\t}\n","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mldsa/mldsa.go#L280-L316","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npub, err := mldsa.NewPublicKey65(pemBytes)   // PEM still encoded\n\n// after\nblock, _ := pem.Decode(pemBytes)\nspki, err := x509.ParsePKIXPublicKey(block.Bytes)\n// then convert via the mldsa helpers, or\npub, err := mldsa.NewPublicKey65(raw1952Bytes)","handlingStrategy":"validation","validationCode":"want := mldsa.PublicKeySizeForVariant(v) // 1312/1952/2592\nif len(pk) != want {\n    return fmt.Errorf(\"public key must be %d bytes, got %d\", want, len(pk))\n}","typeGuard":"func isMLDSA44PublicKey(pk []byte) bool { return len(pk) == 1312 }","tryCatchPattern":null,"preventionTips":["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."],"tags":["crypto","mldsa","fips","validation","input-length"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}