{"record":{"id":"0d1c0dada5d6c9fd","repo":"golang/go","slug":"ed25519-bad-private-key-length-l","errorCode":null,"errorMessage":"ed25519: bad private key length: {l}","messagePattern":"ed25519: bad private key length: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/ed25519/ed25519.go","lineNumber":114,"sourceCode":"\ts, err := priv.s.SetBytesWithClamping(h[:32])\n\tif err != nil {\n\t\tpanic(\"ed25519: internal error: setting scalar failed\")\n\t}\n\tA := (&edwards25519.Point{}).ScalarBaseMult(s)\n\tcopy(priv.pub[:], A.Bytes())\n\n\tcopy(priv.prefix[:], h[32:])\n}\n\nfunc NewPrivateKey(priv []byte) (*PrivateKey, error) {\n\tp := &PrivateKey{}\n\treturn newPrivateKey(p, priv)\n}\n\nfunc newPrivateKey(priv *PrivateKey, privBytes []byte) (*PrivateKey, error) {\n\tfips140.RecordApproved()\n\tif l := len(privBytes); l != privateKeySize {\n\t\treturn nil, errors.New(\"ed25519: bad private key length: \" + strconv.Itoa(l))\n\t}\n\n\tcopy(priv.seed[:], privBytes[:32])\n\n\ths := sha512.New()\n\ths.Write(priv.seed[:])\n\th := hs.Sum(make([]byte, 0, sha512Size))\n\n\tif _, err := priv.s.SetBytesWithClamping(h[:32]); err != nil {\n\t\tpanic(\"ed25519: internal error: setting scalar failed\")\n\t}\n\t// Note that we are not decompressing the public key point here,\n\t// because it takes > 20% of the time of a signature generation.\n\t// Signing doesn't use it as a point anyway.\n\tcopy(priv.pub[:], privBytes[32:])\n\n\tcopy(priv.prefix[:], h[32:])\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/ed25519/ed25519.go#L96-L132","documentation":"Returned by NewPrivateKey when privBytes is not exactly privateKeySize (64 = 32-byte seed + 32-byte public key) bytes. The FIPS PrivateKey type bundles seed and public key as specified by the standard encoding.","triggerScenarios":"Calling fips140/ed25519.NewPrivateKey(privBytes) with a byte slice whose length is not 64 — common offenders are 32 (seed only), 96 (some PKCS#8 forms), or arbitrary raw bytes.","commonSituations":"Confusing the 32-byte seed with the 64-byte private key; passing a PKCS#8 / OpenSSH-wrapped private key without first extracting the raw 64-byte core; passing the 32-byte scalar instead of the seed+pubkey blob.","solutions":["Supply exactly 64 raw bytes in the order [32-byte seed][32-byte public key].","If you only have the seed, use NewPrivateKeyFromSeed and then read the public key from the result.","For PKCS#8 PEM inputs, parse with the standard encoding package first and extract the inner 32-byte seed, then call NewPrivateKeyFromSeed."],"exampleFix":"// before: only the 32-byte seed\npriv, err := ed25519.NewPrivateKey(seed32)\n\n// after\npriv, err := ed25519.NewPrivateKeyFromSeed(seed32)\n// or, if you have seed+pub concatenated (64 bytes):\npriv, err := ed25519.NewPrivateKey(seedPlusPub64)","handlingStrategy":"validation","validationCode":"const ed25519PrivSize = 64\nif len(b) != ed25519PrivSize {\n    return nil, fmt.Errorf(\"ed25519 private key must be %d bytes, got %d\", ed25519PrivSize, len(b))\n}\nreturn ed25519.NewPrivateKey(b)","typeGuard":null,"tryCatchPattern":"priv, err := ed25519.NewPrivateKey(b)\nif err != nil {\n    if strings.Contains(err.Error(), \"bad private key length\") {\n        // caller passed wrong-sized blob; surface clearly\n        return nil, fmt.Errorf(\"invalid ed25519 private key encoding: %w\", err)\n    }\n    return nil, err\n}","preventionTips":["Parse PKCS#8 / PEM with stdlib first; extract the inner 32-byte seed; use FromSeed.","Document the 64-byte seed+pub layout at every import boundary.","Test key import with both seed (32B) and full private key (64B) inputs."],"tags":["crypto","ed25519","fips140","validation","key-import"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}