{"record":{"id":"6abdf9024d291b76","repo":"golang/go","slug":"ecdsa-private-key-is-zero","errorCode":null,"errorMessage":"ecdsa: private key is zero","messagePattern":"ecdsa: private key is zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ecdsa/ecdsa.go","lineNumber":177,"sourceCode":"\n// NewPrivateKey creates a new ECDSA private key from the given D and Q byte\n// slices. D must be the fixed-length big-endian encoding of the private scalar,\n// and Q must be the compressed or uncompressed encoding of the public point.\nfunc NewPrivateKey[P Point[P]](c *Curve[P], D, Q []byte) (*PrivateKey, error) {\n\tfips140.RecordApproved()\n\tpub, err := NewPublicKey(c, Q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(D) != c.N.Size() {\n\t\treturn nil, errors.New(\"ecdsa: invalid private key length\")\n\t}\n\td, err := bigmod.NewNat().SetBytes(D, c.N)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif d.IsZero() == 1 {\n\t\treturn nil, errors.New(\"ecdsa: private key is zero\")\n\t}\n\tpriv := &PrivateKey{pub: *pub, d: d.Bytes(c.N)}\n\treturn priv, nil\n}\n\n// NewPublicKey creates a new ECDSA public key from the given Q byte slice.\n// Q must be the compressed or uncompressed encoding of the public point.\nfunc NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) {\n\t// SetBytes checks that Q is a valid point on the curve, and that its\n\t// coordinates are reduced modulo p, fulfilling the requirements of SP\n\t// 800-89, Section 5.3.2.\n\tif len(Q) < 1 || Q[0] == 0 {\n\t\treturn nil, errors.New(\"ecdsa: invalid public key encoding\")\n\t}\n\t_, err := c.newPoint().SetBytes(Q)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ecdsa/ecdsa.go#L159-L195","documentation":"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.","triggerScenarios":"Calling NewPrivateKey with a D slice of the correct length but all bytes zero.","commonSituations":"Uninitialized/zeroed key buffers, a freshly-allocated slice never written to, or a derandomized/test fixture that is accidentally zero.","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."],"exampleFix":"// before\npriv, err := ecdsa.NewPrivateKey(curve, make([]byte, curve.N.Size())) // all zero\n\n// after: use the generator\npriv, err := ecdsa.GenerateKey(curve, rand.Reader)","handlingStrategy":"validation","validationCode":"if allZero(D) {\n    return errors.New(\"ecdsa private key is zero\")\n}\nreturn ecdsa.NewPrivateKey(curve, D, Q)","typeGuard":"func nonZeroScalar(D []byte) bool {\n    for _, b := range D { if b != 0 { return true } }\n    return false\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["go","crypto","fips","ecdsa","key-validation"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}