golang/go · error
ecdsa: hash cannot be empty
Error message
ecdsa: hash cannot be empty
What it means
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.
Source
Thrown at src/crypto/internal/fips140/ecdsa/ecdsa.go:287
// randomPoint rejects a candidate for being higher than the modulus.
var testingOnlyRejectionSamplingLooped func()
// Signature is an ECDSA signature, where r and s are represented as big-endian
// byte slices of the same length as the curve order.
type Signature struct {
R, S []byte
}
// Sign signs a hash (which should be the result of hashing a larger message with
// the hash function H) using the private key, priv. If the hash is longer than
// the bit-length of the private key's curve order, the hash will be truncated
// to that length.
func Sign[P Point[P], H hash.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
if priv.pub.curve != c.curve {
return nil, errors.New("ecdsa: private key does not match curve")
}
if len(hash) == 0 {
return nil, errors.New("ecdsa: hash cannot be empty")
}
fips140.RecordApproved()
fipsSelfTest()
// Random ECDSA is dangerous, because a failure of the RNG would immediately
// leak the private key. Instead, we use a "hedged" approach, as specified
// in draft-irtf-cfrg-det-sigs-with-noise-04, Section 4. This has also the
// advantage of closely resembling Deterministic ECDSA.
Z := make([]byte, len(priv.d))
if err := drbg.ReadWithReader(rand, Z); err != nil {
return nil, err
}
// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6
// for the FIPS compliance of this method. In short Z is entropy from the
// main DRBG, of length 3/2 of security_strength, so the nonce is optional
// per SP 800-90Ar1, Section 8.6.7, and the rest is a personalizationView on GitHub (pinned to b6b368adc5)
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.
Example fix
// before sig, err := ecdsa.Sign(curve, sha256.New, priv, rand, nil) // after: pass an actual digest h := sha256.Sum256(message) sig, err := ecdsa.Sign(curve, sha256.New, priv, rand, h[:])
Defensive patterns
Strategy: validation
Validate before calling
if len(hash) == 0 {
return errors.New("hash must be non-empty")
}
return ecdsa.Sign(c, h, priv, rand, hash) Type guard
func hasDigest(hash []byte) bool { return len(hash) > 0 } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Forgetting to call Sum, a nil digest passed by mistake, or an upstream hashing step that returned no bytes.
Related errors
- ecdsa: Sign must be called with a hash, not with crypto.Hash
- ecdsa: hash length does not match hash function
- ecdsa: hash cannot be empty
- crypto/ecdsa: use of hash functions other than SHA-2 or SHA-
- ecdsa: private key scalar is zero or negative
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/4a87352e8d3b76ac.
Report an issue: GitHub.