{"record":{"id":"f75003b9b776048c","repo":"golang/go","slug":"crypto-ecdh-invalid-public-key-f75003","errorCode":null,"errorMessage":"crypto/ecdh: invalid public key","messagePattern":"crypto/ecdh: invalid public key","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/ecdh/x25519.go","lineNumber":74,"sourceCode":"\tpublicKey := make([]byte, x25519PublicKeySize)\n\tx25519Basepoint := [32]byte{9}\n\tx25519ScalarMult(publicKey, key, x25519Basepoint[:])\n\t// We don't check for the all-zero public key here because the scalar is\n\t// never zero because of clamping, and the basepoint is not the identity in\n\t// the prime-order subgroup(s).\n\treturn &PrivateKey{\n\t\tcurve:      c,\n\t\tprivateKey: bytes.Clone(key),\n\t\tpublicKey:  &PublicKey{curve: c, publicKey: publicKey},\n\t}, nil\n}\n\nfunc (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {\n\tif fips140only.Enforced() {\n\t\treturn nil, errors.New(\"crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode\")\n\t}\n\tif len(key) != x25519PublicKeySize {\n\t\treturn nil, errors.New(\"crypto/ecdh: invalid public key\")\n\t}\n\treturn &PublicKey{\n\t\tcurve:     c,\n\t\tpublicKey: bytes.Clone(key),\n\t}, nil\n}\n\nfunc (c *x25519Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {\n\tout := make([]byte, x25519SharedSecretSize)\n\tx25519ScalarMult(out, local.privateKey, remote.publicKey)\n\tif isZero(out) {\n\t\treturn nil, errors.New(\"crypto/ecdh: bad X25519 remote ECDH input: low order point\")\n\t}\n\treturn out, nil\n}\n\nfunc x25519ScalarMult(dst, scalar, point []byte) {\n\tvar e [32]byte","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/ecdh/x25519.go#L56-L92","documentation":"Thrown by x25519Curve.NewPublicKey when the provided key slice is not exactly 32 bytes (x25519PublicKeySize). X25519 public keys are fixed-length per RFC 7748, so any other length is structurally invalid and cannot represent a point on Curve25519. The check runs after the FIPS-140-only mode gate, so it applies in all non-FIPS usage.","triggerScenarios":"Calling ecdh.X25519().NewPublicKey(key) where len(key) != 32. Common triggers: passing a base64/hex-encoded string without decoding, passing a raw elliptic.Unmarshal point, passing a truncated or padded key, or passing an Ed25519 public key (also 32 bytes but semantically different — this won't error but will produce wrong results).","commonSituations":"Reading an X25519 public key from a PEM/DER file and forgetting to extract the raw 32-byte seed; receiving a key over a network protocol that prepends a length prefix or algorithm identifier byte; copying a key from a hex string without hex.DecodeString; mixing up X25519 and Ed25519 key formats.","solutions":["Verify len(key) == 32 before calling NewPublicKey; if the key is hex or base64 encoded, decode it first with hex.DecodeString or base64.Decode.","If loading from PEM, use crypto/x509 to parse the key and then extract the raw bytes rather than feeding the entire PEM/DER blob.","Ensure no extra framing bytes (length prefixes, version tags, algorithm OIDs) are prepended to the raw key material."],"exampleFix":"// before\nraw := []byte(\"MCowBQYDK2VuAyEA...\") // base64 string as bytes\npub, err := ecdh.X25519().NewPublicKey(raw)\n\n// after\ndecoded, err := base64.RawURLEncoding.DecodeString(\"MCowBQYDK2VuAyEA...\")\nif err != nil { return err }\npub, err := ecdh.X25519().NewPublicKey(decoded)","handlingStrategy":"validation","validationCode":"func validateX25519PublicKey(key []byte) error {\n    if len(key) != 32 {\n        return fmt.Errorf(\"x25519 public key must be 32 bytes, got %d\", len(key))\n    }\n    return nil\n}\n// call before: ecdh.X25519().NewPublicKey(key)","typeGuard":"func isValidX25519PublicKey(key []byte) bool {\n    return len(key) == 32\n}","tryCatchPattern":"pub, err := ecdh.X25519().NewPublicKey(key)\nif err != nil {\n    return fmt.Errorf(\"invalid X25519 public key (len=%d, want 32): %w\", len(key), err)\n}","preventionTips":["Always decode hex/base64-encoded keys before passing to NewPublicKey.","Use crypto/x509 for parsing keys from PEM/DER containers.","Assert len(key) == 32 in tests when generating or transforming keys."],"tags":["crypto","ecdh","x25519","key-validation","input-validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}