{"record":{"id":"70610bb93b411f35","repo":"golang/go","slug":"ecdsa-hash-length-does-not-match-hash-function","errorCode":null,"errorMessage":"ecdsa: hash length does not match hash function","messagePattern":"ecdsa: hash length does not match hash function","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/ecdsa/ecdsa.go","lineNumber":330,"sourceCode":"//\n// If random is not nil, the signature is randomized. Most applications should use\n// [crypto/rand.Reader] as random, but unless GODEBUG=cryptocustomrand=1 is set, a\n// secure source of random bytes is always used, and the actual Reader is ignored.\n// The GODEBUG setting will be removed in a future Go release. Instead, use\n// [testing/cryptotest.SetGlobalRandom].\n//\n// If random is nil, Sign will produce a deterministic signature according to RFC\n// 6979. When producing a deterministic signature, opts.HashFunc() must be the\n// function used to produce digest and priv.Curve must be one of\n// [elliptic.P224], [elliptic.P256], [elliptic.P384], or [elliptic.P521].\nfunc (priv *PrivateKey) Sign(random io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {\n\tif opts != nil {\n\t\th := opts.HashFunc()\n\t\tif h == 0 {\n\t\t\treturn nil, errors.New(\"ecdsa: Sign must be called with a hash, not with crypto.Hash(0)\")\n\t\t}\n\t\tif h.Size() != len(digest) {\n\t\t\treturn nil, errors.New(\"ecdsa: hash length does not match hash function\")\n\t\t}\n\t}\n\tif random == nil {\n\t\treturn signRFC6979(priv, digest, opts)\n\t}\n\trandom = rand.CustomReader(random)\n\treturn SignASN1(random, priv, digest)\n}\n\n// GenerateKey generates a new ECDSA private key for the specified curve.\n//\n// Since Go 1.26, a secure source of random bytes is always used, and the Reader is\n// ignored unless GODEBUG=cryptocustomrand=1 is set. This setting will be removed\n// in a future Go release. Instead, use [testing/cryptotest.SetGlobalRandom].\nfunc GenerateKey(c elliptic.Curve, r io.Reader) (*PrivateKey, error) {\n\tif boring.Enabled && rand.IsDefaultReader(r) {\n\t\tx, y, d, err := boring.GenerateKeyECDSA(c.Params().Name)\n\t\tif err != nil {","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/ecdsa/ecdsa.go#L312-L348","documentation":"Thrown by PrivateKey.Sign() when opts is non-nil and the hash function's output size (h.Size()) does not match the length of the provided digest slice. This guards against mismatches where the caller claims to use one hash but provides a digest of a different length, which would truncate or pad incorrectly during signing.","triggerScenarios":"Calling priv.Sign(rand, digest, opts) where len(digest) != opts.HashFunc().Size(). For example, passing a 32-byte SHA-256 digest but specifying crypto.SHA512 (64-byte output), or passing a raw message instead of its hash digest.","commonSituations":"Forgetting to hash the message and passing the raw message bytes as the digest; changing the hash algorithm in opts but not re-hashing the data; mixing up SHA-256 (32 bytes) and SHA-512 (64 bytes) digest sizes; passing a truncated or partial digest.","solutions":["Ensure len(digest) matches opts.HashFunc().Size() — e.g., for crypto.SHA256, the digest must be exactly 32 bytes.","Hash the message immediately before signing using the same hash function specified in opts: digest = sha256.Sum256(msg); then Sign(rand, digest[:], crypto.SHA256).","Double-check the hash function constant matches the one actually used to compute the digest."],"exampleFix":"// before\ndigest := sha512.Sum512(msg) // 64 bytes\nsig, err := priv.Sign(rand.Reader, digest[:], crypto.SHA256) // expects 32 bytes\n\n// after\ndigest := sha512.Sum512(msg)\nsig, err := priv.Sign(rand.Reader, digest[:], crypto.SHA512) // sizes match","handlingStrategy":"validation","validationCode":"func validateDigestLength(digest []byte, h crypto.Hash) error {\n    if h.Size() != len(digest) {\n        return fmt.Errorf(\"digest length %d does not match %s size %d\", len(digest), h, h.Size())\n    }\n    return nil\n}","typeGuard":"func digestMatchesHash(digest []byte, h crypto.Hash) bool {\n    return len(digest) == h.Size()\n}","tryCatchPattern":"sig, err := priv.Sign(rand.Reader, digest, opts)\nif err != nil {\n    return fmt.Errorf(\"signing failed (digest=%d bytes, hash=%s expects %d): %w\",\n        len(digest), opts.HashFunc(), opts.HashFunc().Size(), err)\n}","preventionTips":["Always compute the digest with the same hash function specified in opts.","Add an assertion: if len(digest) != hash.Size() before calling Sign."],"tags":["crypto","ecdsa","signing","hash","input-validation","length-mismatch"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}