golang/go · error
ecdsa: private key scalar too large
Error message
ecdsa: private key scalar too large
What it means
Thrown by privateKeyToFIPS when priv.D.BitLen() exceeds priv.Curve.Params().N.BitLen(). The private key scalar D must be within the range [1, N-1] where N is the curve order. If D's bit length exceeds N's bit length, it cannot be correctly encoded as a fixed-size scalar and would produce an invalid key when converted to the internal FIPS representation.
Source
Thrown at src/crypto/ecdsa/ecdsa.go:599
func publicKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) (*ecdsa.PublicKey, error) {
Q, err := pointFromAffine(pub.Curve, pub.X, pub.Y)
if err != nil {
return nil, err
}
return ecdsa.NewPublicKey(c, Q)
}
var privateKeyCache fips140cache.Cache[PrivateKey, ecdsa.PrivateKey]
func privateKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey) (*ecdsa.PrivateKey, error) {
Q, err := pointFromAffine(priv.Curve, priv.X, priv.Y)
if err != nil {
return nil, err
}
// Reject values that would not get correctly encoded.
if priv.D.BitLen() > priv.Curve.Params().N.BitLen() {
return nil, errors.New("ecdsa: private key scalar too large")
}
if priv.D.Sign() <= 0 {
return nil, errors.New("ecdsa: private key scalar is zero or negative")
}
size := (priv.Curve.Params().N.BitLen() + 7) / 8
const maxScalarSize = 66 // enough for a P-521 private key
if size > maxScalarSize {
return nil, errors.New("ecdsa: internal error: curve size too large")
}
D := priv.D.FillBytes(make([]byte, size, maxScalarSize))
return privateKeyCache.Get(priv, func() (*ecdsa.PrivateKey, error) {
return ecdsa.NewPrivateKey(c, D, Q)
}, func(k *ecdsa.PrivateKey) bool {
return subtle.ConstantTimeCompare(k.PublicKey().Bytes(), Q) == 1 &&
subtle.ConstantTimeCompare(k.Bytes(), D) == 1
})View on GitHub (pinned to b6b368adc5)
Solutions
- Always generate keys using ecdsa.GenerateKey() which produces correctly-sized scalars.
- When importing a private key, validate: if priv.D.Cmp(priv.Curve.Params().N) >= 0 || priv.D.Sign() <= 0, reject the key.
- Reduce D modulo N before setting it: priv.D = new(big.Int).Mod(d, curve.Params().N) — but only if the original value was meant to be a valid scalar (mod reduction changes the key).
Example fix
// before
priv.D = new(big.Int).SetBytes(tooLargeBytes) // may exceed N
// after
n := priv.Curve.Params().N
if priv.D.Cmp(n) >= 0 {
return errors.New("private key scalar out of range")
}
// or better: use ecdsa.GenerateKey for new keys, or validate at import time Defensive patterns
Strategy: validation
Validate before calling
func validatePrivateKeyScalar(d *big.Int, curve elliptic.Curve) error {
n := curve.Params().N
if d.Sign() <= 0 {
return errors.New("private key scalar must be positive")
}
if d.Cmp(n) >= 0 {
return errors.New("private key scalar must be less than curve order N")
}
return nil
} Type guard
func isValidScalar(d *big.Int, curve elliptic.Curve) bool {
n := curve.Params().N
return d.Sign() > 0 && d.Cmp(n) < 0
} Try / catch
// After importing a key:
if err := validatePrivateKeyScalar(priv.D, priv.Curve); err != nil {
return fmt.Errorf("invalid private key: %w", err)
} Prevention
- Always use ecdsa.GenerateKey() for new keys — it guarantees valid scalars.
- Validate D against [1, N-1] at import time from any external format.
- Never manually set priv.D to an arbitrary big.Int without range checking.
When it happens
Trigger: Constructing an ecdsa.PrivateKey with a D value whose bit length exceeds the curve order's bit length. This typically happens when manually setting priv.D to an arbitrary big.Int without validation, or when deserializing a private key from a format that doesn't enforce the scalar range.
Common situations: Manually constructing a PrivateKey struct instead of using GenerateKey; loading keys from non-standard formats that don't validate D against the curve order; bugs in key import code that sets D to a value larger than N; arithmetic errors that produce oversized scalars.
Related errors
- ecdsa: curve not supported by ParseRawPrivateKey
- crypto/ecdh: invalid public key
- ecdsa: invalid uncompressed public key
- ecdsa: curve not supported by ParseUncompressedPublicKey
- ecdsa: curve not supported by PrivateKey.Bytes
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/eaa99e2cd99910ba.
Report an issue: GitHub.