{"record":{"id":"db15ab90c94f7030","repo":"golang/go","slug":"mldsa-context-too-long","errorCode":null,"errorMessage":"mldsa: context too long","messagePattern":"mldsa: context too long","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mldsa/mldsa.go","lineNumber":332,"sourceCode":"\t\treturn nil, errInvalidPublicKeyLength\n\t}\n\n\t// We don't precompute A and t1Hat here, because they would make the\n\t// PublicKey over 68KB. Unlike private keys, public keys are often used to\n\t// verify a signature only once, so precomputation doesn't help as often,\n\t// but they can stay around in memory, for example as part of a TLS\n\t// connection's PeerCertificates, so their size is more of a concern.\n\t// Instead, we compute A and t1Hat on demand in Verify.\n\n\tpub.p = p\n\tcopy(pub.raw[:], pk)\n\tpub.tr = computePublicKeyHash(pk)\n\n\treturn pub, nil\n}\n\nvar (\n\terrContextTooLong    = errors.New(\"mldsa: context too long\")\n\terrMessageHashLength = errors.New(\"mldsa: invalid message hash length\")\n\terrRandomLength      = errors.New(\"mldsa: invalid random length\")\n)\n\nfunc Sign(priv *PrivateKey, msg []byte, context string) ([]byte, error) {\n\tfipsSelfTest()\n\tfips140.RecordApproved()\n\tvar random [32]byte\n\tdrbg.Read(random[:])\n\tμ, err := computeMessageHash(priv.pub.tr[:], msg, context)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn signInternal(priv, &μ, &random), nil\n}\n\nfunc SignDeterministic(priv *PrivateKey, msg []byte, context string) ([]byte, error) {\n\tfipsSelfTest()","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mldsa/mldsa.go#L314-L350","documentation":"ML-DSA binds an optional context string into the signed message digest (the ctx in FIPS 204's M' construction). The standard caps this context at 255 bytes so it fits in a single length-prefixed byte. computeMessageHash enforces the cap on behalf of both Sign and Verify; anything longer is rejected before any hashing happens. The same context must be supplied to both Sign and Verify or verification will later fail.","triggerScenarios":"Calling mldsa.Sign(priv, msg, context) or mldsa.Verify(pub, msg, sig, context) with len(context) > 255.","commonSituations":"Embedding a long URI, JWT, certificate chain, or concatenated metadata blob as the context; copying a 'domain' string from config without length-checking; logging context that grew over time.","solutions":["Cap the context at 255 bytes; if a longer domain separator is needed, hash it down with SHA-256/SHA3-256 and pass the 32-byte digest as the context (the FIPS 204 scheme does not forbid a hash output as ctx).","Validate len(context) <= 255 at the API boundary and surface a clear validation error to the caller.","Keep context a short, stable identifier (application name + version) rather than free-form metadata."],"exampleFix":"// before\nsig, err := mldsa.Sign(priv, msg, longDomainString)\n\n// after\nif len(context) > 255 {\n    sum := sha3.Sum256([]byte(longDomainString))\n    context = string(sum[:])\n}\nsig, err := mldsa.Sign(priv, msg, context)","handlingStrategy":"validation","validationCode":"if len(context) > 255 {\n    return fmt.Errorf(\"mldsa context limited to 255 bytes, got %d\", len(context))\n}","typeGuard":"func isValidContext(ctx string) bool { return len(ctx) <= 255 }","tryCatchPattern":null,"preventionTips":["Keep context a short stable identifier (app name + version).","Hash long domain separators down to 32 bytes before using them as context.","Validate context length at the API boundary so the error names the caller's input."],"tags":["crypto","mldsa","fips","validation","context"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}