golang/go · error
ecdsa: private key is zero
Error message
ecdsa: private key is zero
What it means
Thrown by fips140/ecdsa.NewPrivateKey after the scalar was parsed when d.IsZero() == 1. A zero private scalar is invalid because the corresponding public point would be the identity element and signing would be undefined/leak everything. The zero check runs after SetBytes succeeds, so it catches an all-zero D of the correct length.
Source
Thrown at src/crypto/internal/fips140/ecdsa/ecdsa.go:177
// NewPrivateKey creates a new ECDSA private key from the given D and Q byte
// slices. D must be the fixed-length big-endian encoding of the private scalar,
// and Q must be the compressed or uncompressed encoding of the public point.
func NewPrivateKey[P Point[P]](c *Curve[P], D, Q []byte) (*PrivateKey, error) {
fips140.RecordApproved()
pub, err := NewPublicKey(c, Q)
if err != nil {
return nil, err
}
if len(D) != c.N.Size() {
return nil, errors.New("ecdsa: invalid private key length")
}
d, err := bigmod.NewNat().SetBytes(D, c.N)
if err != nil {
return nil, err
}
if d.IsZero() == 1 {
return nil, errors.New("ecdsa: private key is zero")
}
priv := &PrivateKey{pub: *pub, d: d.Bytes(c.N)}
return priv, nil
}
// NewPublicKey creates a new ECDSA public key from the given Q byte slice.
// Q must be the compressed or uncompressed encoding of the public point.
func NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) {
// SetBytes checks that Q is a valid point on the curve, and that its
// coordinates are reduced modulo p, fulfilling the requirements of SP
// 800-89, Section 5.3.2.
if len(Q) < 1 || Q[0] == 0 {
return nil, errors.New("ecdsa: invalid public key encoding")
}
_, err := c.newPoint().SetBytes(Q)
if err != nil {
return nil, err
}View on GitHub (pinned to b6b368adc5)
Solutions
- Generate the scalar with the approved GenerateKey rather than supplying bytes.
- Check that D is not all zeros before calling NewPrivateKey.
- If sourcing from entropy, verify the RNG actually wrote non-zero bytes.
Example fix
// before priv, err := ecdsa.NewPrivateKey(curve, make([]byte, curve.N.Size())) // all zero // after: use the generator priv, err := ecdsa.GenerateKey(curve, rand.Reader)
Defensive patterns
Strategy: validation
Validate before calling
if allZero(D) {
return errors.New("ecdsa private key is zero")
}
return ecdsa.NewPrivateKey(curve, D, Q) Type guard
func nonZeroScalar(D []byte) bool {
for _, b := range D { if b != 0 { return true } }
return false
} Prevention
- Generate scalars via GenerateKey instead of supplying raw bytes.
- Verify entropy was written before using a key buffer.
- Reject all-zero key material at the import boundary.
When it happens
Trigger: Calling NewPrivateKey with a D slice of the correct length but all bytes zero.
Common situations: Uninitialized/zeroed key buffers, a freshly-allocated slice never written to, or a derandomized/test fixture that is accidentally zero.
Related errors
- ecdsa: invalid private key length
- ecdsa: invalid public key encoding
- ecdsa: private key does not match curve
- ecdsa: private key scalar is zero or negative
- negative coordinate
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/6abdf9024d291b76.
Report an issue: GitHub.