golang/go · error
ecdsa: hash length does not match hash function
Error message
ecdsa: hash length does not match hash function
What it means
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.
Source
Thrown at src/crypto/ecdsa/ecdsa.go:330
//
// If random is not nil, the signature is randomized. Most applications should use
// [crypto/rand.Reader] as random, but unless GODEBUG=cryptocustomrand=1 is set, a
// secure source of random bytes is always used, and the actual Reader is ignored.
// The GODEBUG setting will be removed in a future Go release. Instead, use
// [testing/cryptotest.SetGlobalRandom].
//
// If random is nil, Sign will produce a deterministic signature according to RFC
// 6979. When producing a deterministic signature, opts.HashFunc() must be the
// function used to produce digest and priv.Curve must be one of
// [elliptic.P224], [elliptic.P256], [elliptic.P384], or [elliptic.P521].
func (priv *PrivateKey) Sign(random io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
if opts != nil {
h := opts.HashFunc()
if h == 0 {
return nil, errors.New("ecdsa: Sign must be called with a hash, not with crypto.Hash(0)")
}
if h.Size() != len(digest) {
return nil, errors.New("ecdsa: hash length does not match hash function")
}
}
if random == nil {
return signRFC6979(priv, digest, opts)
}
random = rand.CustomReader(random)
return SignASN1(random, priv, digest)
}
// GenerateKey generates a new ECDSA private key for the specified curve.
//
// Since Go 1.26, a secure source of random bytes is always used, and the Reader is
// ignored unless GODEBUG=cryptocustomrand=1 is set. This setting will be removed
// in a future Go release. Instead, use [testing/cryptotest.SetGlobalRandom].
func GenerateKey(c elliptic.Curve, r io.Reader) (*PrivateKey, error) {
if boring.Enabled && rand.IsDefaultReader(r) {
x, y, d, err := boring.GenerateKeyECDSA(c.Params().Name)
if err != nil {View on GitHub (pinned to b6b368adc5)
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.
Example fix
// before digest := sha512.Sum512(msg) // 64 bytes sig, err := priv.Sign(rand.Reader, digest[:], crypto.SHA256) // expects 32 bytes // after digest := sha512.Sum512(msg) sig, err := priv.Sign(rand.Reader, digest[:], crypto.SHA512) // sizes match
Defensive patterns
Strategy: validation
Validate before calling
func validateDigestLength(digest []byte, h crypto.Hash) error {
if h.Size() != len(digest) {
return fmt.Errorf("digest length %d does not match %s size %d", len(digest), h, h.Size())
}
return nil
} Type guard
func digestMatchesHash(digest []byte, h crypto.Hash) bool {
return len(digest) == h.Size()
} Try / catch
sig, err := priv.Sign(rand.Reader, digest, opts)
if err != nil {
return fmt.Errorf("signing failed (digest=%d bytes, hash=%s expects %d): %w",
len(digest), opts.HashFunc(), opts.HashFunc().Size(), err)
} Prevention
- Always compute the digest with the same hash function specified in opts.
- Add an assertion: if len(digest) != hash.Size() before calling Sign.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ecdsa: Sign must be called with a hash, not with crypto.Hash
- ecdsa: hash cannot be empty
- ecdsa: requested hash function unavailable:
- crypto/ecdsa: use of hash functions other than SHA-2 or SHA-
- ecdsa: hash cannot be empty
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/70610bb93b411f35.
Report an issue: GitHub.