{"record":{"id":"e78ae703f38d23c3","repo":"golang/go","slug":"ed25519-bad-ed25519ph-message-hash-length-l","errorCode":null,"errorMessage":"ed25519: bad Ed25519ph message hash length: {l}","messagePattern":"ed25519: bad Ed25519ph message hash length: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ed25519/ed25519.go","lineNumber":190,"sourceCode":"\nfunc sign(signature []byte, priv *PrivateKey, message []byte) []byte {\n\tfipsSelfTest()\n\tfips140.RecordApproved()\n\treturn signWithDom(signature, priv, message, domPrefixPure, \"\")\n}\n\nfunc SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) {\n\t// Outline the function body so that the returned signature can be\n\t// stack-allocated.\n\tsignature := make([]byte, signatureSize)\n\treturn signPH(signature, priv, message, context)\n}\n\nfunc signPH(signature []byte, priv *PrivateKey, message []byte, context string) ([]byte, error) {\n\tfipsSelfTest()\n\tfips140.RecordApproved()\n\tif l := len(message); l != sha512Size {\n\t\treturn nil, errors.New(\"ed25519: bad Ed25519ph message hash length: \" + strconv.Itoa(l))\n\t}\n\tif l := len(context); l > 255 {\n\t\treturn nil, errors.New(\"ed25519: bad Ed25519ph context length: \" + strconv.Itoa(l))\n\t}\n\treturn signWithDom(signature, priv, message, domPrefixPh, context), nil\n}\n\nfunc SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) {\n\t// Outline the function body so that the returned signature can be\n\t// stack-allocated.\n\tsignature := make([]byte, signatureSize)\n\treturn signCtx(signature, priv, message, context)\n}\n\nfunc signCtx(signature []byte, priv *PrivateKey, message []byte, context string) ([]byte, error) {\n\tfipsSelfTest()\n\t// FIPS 186-5 specifies Ed25519 and Ed25519ph (with context), but not Ed25519ctx.\n\tfips140.RecordNonApproved()","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ed25519/ed25519.go#L172-L208","documentation":"Returned by SignPH (Ed25519ph) when the message argument is not exactly sha512Size (64) bytes. Ed25519ph signs a pre-computed SHA-512 hash of the message, so the API contract requires the caller to pass that 64-byte digest, not the raw message.","triggerScenarios":"Calling fips140/ed25519.SignPH(priv, message, context) where len(message) != 64 — typically because the raw message or a SHA-256 hash was passed instead of a SHA-512 hash.","commonSituations":"Passing the plaintext message instead of its SHA-512 hash; passing a SHA-256 (32-byte) or SHA-384 hash; assuming SignPH hashes internally (it does not — it expects the digest).","solutions":["Pre-hash the message with SHA-512 and pass the resulting 64-byte digest to SignPH.","If you want the library to hash for you, use the pure Ed25519 Sign instead of Ed25519ph.","Verify interoperability: both signer and verifier must agree on the SHA-512 pre-hash variant."],"exampleFix":"// before\nsig, err := ed25519.SignPH(priv, []byte(\"hello\"), \"\")\n\n// after\ndigest := sha512.Sum512([]byte(\"hello\"))\nsig, err := ed25519.SignPH(priv, digest[:], \"\")","handlingStrategy":"validation","validationCode":"if len(message) != 64 {\n    digest := sha512.Sum512(message)\n    message = digest[:]\n}\nsig, err := ed25519.SignPH(priv, message, context)","typeGuard":null,"tryCatchPattern":"sig, err := ed25519.SignPH(priv, message, context)\nif err != nil {\n    if strings.Contains(err.Error(), \"bad Ed25519ph message hash length\") {\n        return nil, fmt.Errorf(\"SignPH needs a 64-byte SHA-512 digest, got %d bytes\", len(message))\n    }\n    return nil, err\n}","preventionTips":["Document that Ed25519ph expects a SHA-512 digest, not the raw message.","Use pure Ed25519 Sign if you want the library to hash internally.","Make signer and verifier agree on the variant."],"tags":["crypto","ed25519","ed25519ph","fips140","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}