{"record":{"id":"27274a574ec53c40","repo":"golang/go","slug":"ed25519-bad-public-key","errorCode":null,"errorMessage":"ed25519: bad public key","messagePattern":"ed25519: bad public key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ed25519/ed25519.go","lineNumber":147,"sourceCode":"\tcopy(priv.pub[:], privBytes[32:])\n\n\tcopy(priv.prefix[:], h[32:])\n\n\treturn priv, nil\n}\n\nfunc NewPublicKey(pub []byte) (*PublicKey, error) {\n\tp := &PublicKey{}\n\treturn newPublicKey(p, pub)\n}\n\nfunc newPublicKey(pub *PublicKey, pubBytes []byte) (*PublicKey, error) {\n\tif l := len(pubBytes); l != publicKeySize {\n\t\treturn nil, errors.New(\"ed25519: bad public key length: \" + strconv.Itoa(l))\n\t}\n\t// SetBytes checks that the point is on the curve.\n\tif _, err := pub.a.SetBytes(pubBytes); err != nil {\n\t\treturn nil, errors.New(\"ed25519: bad public key\")\n\t}\n\tcopy(pub.aBytes[:], pubBytes)\n\treturn pub, nil\n}\n\n// Domain separation prefixes used to disambiguate Ed25519/Ed25519ph/Ed25519ctx.\n// See RFC 8032, Section 2 and Section 5.1.\nconst (\n\t// domPrefixPure is empty for pure Ed25519.\n\tdomPrefixPure = \"\"\n\t// domPrefixPh is dom2(phflag=1) for Ed25519ph. It must be followed by the\n\t// uint8-length prefixed context.\n\tdomPrefixPh = \"SigEd25519 no Ed25519 collisions\\x01\"\n\t// domPrefixCtx is dom2(phflag=0) for Ed25519ctx. It must be followed by the\n\t// uint8-length prefixed context.\n\tdomPrefixCtx = \"SigEd25519 no Ed25519 collisions\\x00\"\n)\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ed25519/ed25519.go#L129-L165","documentation":"Returned by NewPublicKey after SetBytes fails — the 32 bytes decoded to a point that is not on the Ed25519 curve (or is one of the excluded low-order points). Length is correct but the bytes do not represent a valid group element.","triggerScenarios":"Calling NewPublicKey with 32 bytes that are random, corrupted, or a valid 32-byte blob from a different curve (e.g. X25519 public key, or an Ed448-truncated key).","commonSituations":"Mixing up X25519 (ECDH) and Ed25519 (signing) public keys — both 32 bytes; corrupted key material from storage/network; feeding an identity element that the encoding explicitly rejects; typos in pasted keys.","solutions":["Confirm the bytes were produced by an Ed25519 key generation, not X25519 or another curve.","Re-fetch the public key from the authoritative source to rule out corruption.","Surface the error to the user as 'untrusted public key is malformed' — do not fall back to a default key."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"pub, err := ed25519.NewPublicKey(b)\nif err != nil {\n    if strings.Contains(err.Error(), \"bad public key\") && !strings.Contains(err.Error(), \"length\") {\n        // length OK but point off-curve\n        return nil, ErrKeyNotOnCurve\n    }\n    return nil, err\n}","preventionTips":["Treat off-curve public keys as adversarial — never fall back to a default.","Distinguish X25519 (ECDH) from Ed25519 (signing) at the type/import layer.","Verify key origin before import."],"tags":["crypto","ed25519","fips140","key-validation","curve"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}