golang/go · critical
zero parameter
Error message
zero parameter
What it means
errZeroParam ('zero parameter') is thrown in signLegacy (ecdsa_legacy.go:110-111) when the curve order N.Sign() == 0, i.e. the curve's Params().N is zero. A curve with a zero order is degenerate/invalid; signing math (modular inverse, reduction mod N) would divide by zero. This is a guard against malformed custom curves.
Source
Thrown at src/crypto/ecdsa/ecdsa_legacy.go:57
// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4,
// we use the left-most bits of the hash to match the bit-length of the order of
// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
orderBits := c.Params().N.BitLen()
orderBytes := (orderBits + 7) / 8
if len(hash) > orderBytes {
hash = hash[:orderBytes]
}
ret := new(big.Int).SetBytes(hash)
excess := len(hash)*8 - orderBits
if excess > 0 {
ret.Rsh(ret, uint(excess))
}
return ret
}
var errZeroParam = errors.New("zero parameter")
// Sign signs a hash (which should be the result of hashing a larger message)
// 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. It
// returns the signature as a pair of integers. Most applications should use
// [SignASN1] instead of dealing directly with r, s.
//
// The signature is randomized. 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 Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
sig, err := SignASN1(rand, priv, hash)
if err != nil {
return nil, nil, err
}
r, s = new(big.Int), new(big.Int)View on GitHub (pinned to b6b368adc5)
Solutions
- Use a well-known curve (elliptic.P256 etc.) instead of a custom one; verify Params().N is a positive prime before signing.
- If a custom curve is required, populate Params().N correctly (the curve order) and validate it is non-zero.
- Validate priv.Curve.Params().N.Sign() > 0 before invoking Sign.
Example fix
// before
params := &elliptic.CurveParams{Name: "bad", N: big.NewInt(0)} // N zero
priv := &ecdsa.PrivateKey{PublicKey: ecdsa.PublicKey{Curve: params}}
_, err := ecdsa.Sign(rand.Reader, priv, hash) // -> error 245
// after
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // N correctly set Defensive patterns
Strategy: validation
Validate before calling
if priv.Curve == nil || priv.Curve.Params().N == nil || priv.Curve.Params().N.Sign() == 0 {
return errors.New("curve order N must be a positive prime")
} Type guard
func curveOrderValid(c elliptic.Curve) bool {
return c != nil && c.Params().N != nil && c.Params().N.Sign() > 0
} Prevention
- Avoid custom elliptic.Curve implementations; use the standard NIST curves.
- When implementing a curve, populate Params().N with the correct curve order.
- Validate N is a positive prime before any signing operation.
When it happens
Trigger: Calling ecdsa.Sign / SignASN1 on a PrivateKey whose Curve.Params().N == big.Int(0). Reached only via the legacy (non-FIPS) signing path for custom curves. Happens with a hand-rolled elliptic.Curve implementation that returns a zero N, or a corrupted curve parameter.
Common situations: Implementing a custom elliptic.Curve and forgetting to populate N; loading a curve from a misconfigured registry; porting curve params where N was dropped.
Related errors
- ecdsa: private key scalar is zero or negative
- negative coordinate
- overflowing coordinate
- ecdsa: public key point is the infinity
- crypto/dsa: invalid public key
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/50dcfb03654ee9cc.
Report an issue: GitHub.