{"record":{"id":"4a87352e8d3b76ac","repo":"golang/go","slug":"ecdsa-hash-cannot-be-empty-4a8735","errorCode":null,"errorMessage":"ecdsa: hash cannot be empty","messagePattern":"ecdsa: hash cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ecdsa/ecdsa.go","lineNumber":287,"sourceCode":"// randomPoint rejects a candidate for being higher than the modulus.\nvar testingOnlyRejectionSamplingLooped func()\n\n// Signature is an ECDSA signature, where r and s are represented as big-endian\n// byte slices of the same length as the curve order.\ntype Signature struct {\n\tR, S []byte\n}\n\n// Sign signs a hash (which should be the result of hashing a larger message with\n// the hash function H) using the private key, priv. If the hash is longer than\n// the bit-length of the private key's curve order, the hash will be truncated\n// to that length.\nfunc Sign[P Point[P], H hash.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {\n\tif priv.pub.curve != c.curve {\n\t\treturn nil, errors.New(\"ecdsa: private key does not match curve\")\n\t}\n\tif len(hash) == 0 {\n\t\treturn nil, errors.New(\"ecdsa: hash cannot be empty\")\n\t}\n\tfips140.RecordApproved()\n\tfipsSelfTest()\n\n\t// Random ECDSA is dangerous, because a failure of the RNG would immediately\n\t// leak the private key. Instead, we use a \"hedged\" approach, as specified\n\t// in draft-irtf-cfrg-det-sigs-with-noise-04, Section 4. This has also the\n\t// advantage of closely resembling Deterministic ECDSA.\n\n\tZ := make([]byte, len(priv.d))\n\tif err := drbg.ReadWithReader(rand, Z); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6\n\t// for the FIPS compliance of this method. In short Z is entropy from the\n\t// main DRBG, of length 3/2 of security_strength, so the nonce is optional\n\t// per SP 800-90Ar1, Section 8.6.7, and the rest is a personalization","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ecdsa/ecdsa.go#L269-L305","documentation":"Thrown by fips140/ecdsa.Sign when len(hash) == 0. Sign expects the output of hashing a larger message; an empty hash is rejected before any self-test or signing occurs. The hash is later truncated to the curve order bit-length, but it must be non-empty.","triggerScenarios":"Calling Sign with an empty hash slice — e.g. hashing was skipped, the digest variable was never assigned, or a message of zero length produced an unintended empty buffer.","commonSituations":"Forgetting to call Sum, a nil digest passed by mistake, or an upstream hashing step that returned no bytes.","solutions":["Ensure the hash argument is a real digest: compute it via the hash function's Sum and pass the result.","Guard len(hash) > 0 before calling Sign.","If the message is empty, hash the empty message explicitly rather than passing an empty slice."],"exampleFix":"// before\nsig, err := ecdsa.Sign(curve, sha256.New, priv, rand, nil)\n\n// after: pass an actual digest\nh := sha256.Sum256(message)\nsig, err := ecdsa.Sign(curve, sha256.New, priv, rand, h[:])","handlingStrategy":"validation","validationCode":"if len(hash) == 0 {\n    return errors.New(\"hash must be non-empty\")\n}\nreturn ecdsa.Sign(c, h, priv, rand, hash)","typeGuard":"func hasDigest(hash []byte) bool { return len(hash) > 0 }","tryCatchPattern":null,"preventionTips":["Always pass a computed digest, never nil.","Hash the (possibly empty) message explicitly.","Use the same hash function H as declared in the type parameter."],"tags":["go","crypto","fips","ecdsa","signing","input-validation"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}