{"record":{"id":"3e304c58009ef7d0","repo":"golang/go","slug":"ecdsa-private-key-scalar-is-zero-or-negative","errorCode":null,"errorMessage":"ecdsa: private key scalar is zero or negative","messagePattern":"ecdsa: private key scalar is zero or negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/ecdsa/ecdsa.go","lineNumber":602,"sourceCode":"\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})\n}\n\n// pointFromAffine is used to convert the PublicKey to a nistec SetBytes input.","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/ecdsa/ecdsa.go#L584-L620","documentation":"Thrown by privateKeyToFIPS when converting a legacy crypto/ecdsa PrivateKey to its FIPS nistec form. The guard checks priv.D.Sign() <= 0, rejecting a private scalar that is zero or negative. A valid ECDSA private key must be a positive integer in [1, N-1]; zero/negative is either corrupted input, a mis-encoded key, or an uninitialized (*big.Int)(nil)-adjacent value.","triggerScenarios":"Called from ecdsa.Sign / SignASN1 / SignReader (ecdsa.go:301,425,459) when priv.D is zero or has a negative sign. Happens when a PrivateKey is constructed by hand with priv.D = big.NewInt(0), when a key is parsed from malformed encoding that yields a zero/invalid scalar, or when unmarshaling logic leaves D unset and a zero default is passed.","commonSituations":"Importing a private key from a corrupt PEM/DER file, deserializing a key from an untrusted source, copy-paste errors that zero out D, or test fixtures that forgot to populate the scalar.","solutions":["Verify priv.D is set and in the range [1, N-1] before calling Sign/SignASN1; load keys only via x509.ParseECPrivateKey / ParsePKCS8PrivateKey.","Regenerate the key with ecdsa.GenerateKey if the source scalar is corrupt.","If loading from raw bytes, build the key with D.SetBytes and validate it is non-zero and below the curve order N."],"exampleFix":"// before\npriv := new(ecdsa.PrivateKey)\npriv.D = big.NewInt(0) // corrupt/empty\nsig, err := ecdsa.SignASN1(rand.Reader, priv, hash) // -> error 240\n\n// after\npriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\nif err != nil { return err }\nsig, err := ecdsa.SignASN1(rand.Reader, priv, hash)","handlingStrategy":"validation","validationCode":"if priv.D == nil || priv.D.Sign() <= 0 {\n    return errors.New(\"private key scalar must be positive\")\n}\nN := priv.Curve.Params().N\nif priv.D.Cmp(N) >= 0 {\n    return errors.New(\"private key scalar must be < curve order\")\n}","typeGuard":"func validPrivateKeyScalar(priv *ecdsa.PrivateKey) bool {\n    return priv != nil && priv.D != nil && priv.D.Sign() > 0 && priv.D.Cmp(priv.Curve.Params().N) < 0\n}","tryCatchPattern":"sig, err := ecdsa.SignASN1(rand.Reader, priv, hash)\nif err != nil {\n    if strings.Contains(err.Error(), \"private key scalar is zero or negative\") {\n        // key is corrupt; regenerate or reject\n    }\n    return err\n}","preventionTips":["Always generate keys with ecdsa.GenerateKey; load stored keys via x509.ParseECPrivateKey/ParsePKCS8PrivateKey.","Never hand-construct PrivateKey.D; if you must, validate it is in [1, N-1].","Treat externally-supplied keys as untrusted and validate D before use."],"tags":["go","crypto","ecdsa","fips","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}