{"record":{"id":"bb781abccc3fdd07","repo":"golang/go","slug":"crypto-ecdh-public-key-is-the-identity-element","errorCode":null,"errorMessage":"crypto/ecdh: public key is the identity element","messagePattern":"crypto/ecdh: public key is the identity element","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ecdh/ecdh.go","lineNumber":252,"sourceCode":"\tfipsSelfTest()\n\tfips140.RecordApproved()\n\treturn ecdh(c, k, peer)\n}\n\nfunc ecdh[P Point[P]](c *Curve[P], k *PrivateKey, peer *PublicKey) ([]byte, error) {\n\tif c.curve != k.pub.curve {\n\t\treturn nil, errors.New(\"crypto/ecdh: mismatched curves\")\n\t}\n\tif k.pub.curve != peer.curve {\n\t\treturn nil, errors.New(\"crypto/ecdh: mismatched curves\")\n\t}\n\n\t// This applies the Shared Secret Computation of the Ephemeral Unified Model\n\t// scheme specified in NIST SP 800-56A Rev. 3, Section 6.1.2.2.\n\n\t// Per Section 5.6.2.3.4, Step 1, reject the identity element (0x00).\n\tif len(k.pub.q) == 1 {\n\t\treturn nil, errors.New(\"crypto/ecdh: public key is the identity element\")\n\t}\n\n\t// SetBytes checks that (x, y) are reduced modulo p, and that they are on\n\t// the curve, performing Steps 2-3 of Section 5.6.2.3.4.\n\tp, err := c.newPoint().SetBytes(peer.q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Compute P according to Section 5.7.1.2.\n\tif _, err := p.ScalarMult(p, k.d); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// BytesX checks that the result is not the identity element, and returns the\n\t// x-coordinate of the result, performing Steps 2-5 of Section 5.7.1.2.\n\treturn p.BytesX()\n}","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ecdh/ecdh.go#L234-L270","documentation":"Thrown by fips140/ecdh.ecdh when len(k.pub.q) == 1, i.e. the LOCAL private key's embedded public point is encoded as the identity element (single 0x00 byte). This implements SP 800-56A Rev. 3 §5.6.2.3.4 Step 1. The peer's validity is checked separately via SetBytes and the later ScalarMult/BytesX; this guard specifically rejects a malformed local key whose public point is the identity.","triggerScenarios":"Calling ECDH with a PrivateKey whose pub.q field is the single-byte 0x00 identity encoding. Normally impossible through NewPrivateKey (which rejects such points), so it implies a PrivateKey assembled by hand, deserialized unsafely, or corrupted.","commonSituations":"Constructing a PrivateKey struct literal or unmarshaling it in a way that bypasses NewPrivateKey validation; memory/serialization corruption of the public point.","solutions":["Always construct PrivateKey values through NewPrivateKey (or GenerateKey) so the public point is validated.","If you deserialize a PrivateKey, re-validate it by re-running NewPrivateKey on its bytes before use.","Sanity-check that len(priv.pub.q) > 1 before calling ECDH."],"exampleFix":"// before: priv assembled directly, pub.q == []byte{0x00}\nsecret, err := ecdh.ECDH(curve, malformedPriv, peer)\n\n// after: rebuild the key through the validating constructor\npriv, err := ecdh.NewPrivateKey(curve, priv.d) // re-validates public point\nif err != nil { return err }\nsecret, err := ecdh.ECDH(curve, priv, peer)","handlingStrategy":"validation","validationCode":"// Reject a local private key whose public point is the identity.\nif len(priv.PublicKey().Bytes()) <= 1 {\n    return errors.New(\"local public key is the identity element\")\n}","typeGuard":"func localKeyIsValid(priv *ecdh.PrivateKey) bool {\n    return len(priv.PublicKey().Bytes()) > 1\n}","tryCatchPattern":null,"preventionTips":["Always build PrivateKey via NewPrivateKey/GenerateKey so the public point is validated.","Re-validate deserialized keys through NewPrivateKey before use.","Never assemble a PrivateKey struct literal by hand."],"tags":["go","crypto","fips","ecdh","key-validation","identity-element"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}