{"record":{"id":"eaa99e2cd99910ba","repo":"golang/go","slug":"ecdsa-private-key-scalar-too-large","errorCode":null,"errorMessage":"ecdsa: private key scalar too large","messagePattern":"ecdsa: private key scalar too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/ecdsa/ecdsa.go","lineNumber":599,"sourceCode":"func publicKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) (*ecdsa.PublicKey, error) {\n\tQ, err := pointFromAffine(pub.Curve, pub.X, pub.Y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ecdsa.NewPublicKey(c, Q)\n}\n\nvar privateKeyCache fips140cache.Cache[PrivateKey, ecdsa.PrivateKey]\n\nfunc privateKeyToFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey) (*ecdsa.PrivateKey, error) {\n\tQ, err := pointFromAffine(priv.Curve, priv.X, priv.Y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Reject values that would not get correctly encoded.\n\tif priv.D.BitLen() > priv.Curve.Params().N.BitLen() {\n\t\treturn nil, errors.New(\"ecdsa: private key scalar too large\")\n\t}\n\tif priv.D.Sign() <= 0 {\n\t\treturn nil, errors.New(\"ecdsa: private key scalar is zero or negative\")\n\t}\n\n\tsize := (priv.Curve.Params().N.BitLen() + 7) / 8\n\tconst maxScalarSize = 66 // enough for a P-521 private key\n\tif size > maxScalarSize {\n\t\treturn nil, errors.New(\"ecdsa: internal error: curve size too large\")\n\t}\n\tD := priv.D.FillBytes(make([]byte, size, maxScalarSize))\n\n\treturn privateKeyCache.Get(priv, func() (*ecdsa.PrivateKey, error) {\n\t\treturn ecdsa.NewPrivateKey(c, D, Q)\n\t}, func(k *ecdsa.PrivateKey) bool {\n\t\treturn subtle.ConstantTimeCompare(k.PublicKey().Bytes(), Q) == 1 &&\n\t\t\tsubtle.ConstantTimeCompare(k.Bytes(), D) == 1\n\t})","sourceCodeStart":581,"sourceCodeEnd":617,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/ecdsa/ecdsa.go#L581-L617","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\npriv.D = new(big.Int).SetBytes(tooLargeBytes) // may exceed N\n\n// after\nn := priv.Curve.Params().N\nif priv.D.Cmp(n) >= 0 {\n    return errors.New(\"private key scalar out of range\")\n}\n// or better: use ecdsa.GenerateKey for new keys, or validate at import time","handlingStrategy":"validation","validationCode":"func validatePrivateKeyScalar(d *big.Int, curve elliptic.Curve) error {\n    n := curve.Params().N\n    if d.Sign() <= 0 {\n        return errors.New(\"private key scalar must be positive\")\n    }\n    if d.Cmp(n) >= 0 {\n        return errors.New(\"private key scalar must be less than curve order N\")\n    }\n    return nil\n}","typeGuard":"func isValidScalar(d *big.Int, curve elliptic.Curve) bool {\n    n := curve.Params().N\n    return d.Sign() > 0 && d.Cmp(n) < 0\n}","tryCatchPattern":"// After importing a key:\nif err := validatePrivateKeyScalar(priv.D, priv.Curve); err != nil {\n    return fmt.Errorf(\"invalid private key: %w\", err)\n}","preventionTips":["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."],"tags":["crypto","ecdsa","private-key","key-validation","scalar-range","input-validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}