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

  1. Ensure len(digest) matches opts.HashFunc().Size() — e.g., for crypto.SHA256, the digest must be exactly 32 bytes.
  2. Hash the message immediately before signing using the same hash function specified in opts: digest = sha256.Sum256(msg); then Sign(rand, digest[:], crypto.SHA256).
  3. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/70610bb93b411f35. Report an issue: GitHub.