golang/go · error

ed25519: bad seed length: {l}

Error message

ed25519: bad seed length: {l}

What it means

Returned by NewPrivateKeyFromSeed when the seed is not exactly seedSize (32) bytes. Ed25519 per RFC 8032 fixes the seed at 32 bytes; the seed is hashed with SHA-512 internally to derive the scalar and prefix, so any other length is unrecoverable.

Source

Thrown at src/crypto/internal/fips140/ed25519/ed25519.go:84

}

func generateKey(priv *PrivateKey) (*PrivateKey, error) {
	fips140.RecordApproved()
	drbg.Read(priv.seed[:])
	precomputePrivateKey(priv)
	fipsPCT(priv)
	return priv, nil
}

func NewPrivateKeyFromSeed(seed []byte) (*PrivateKey, error) {
	priv := &PrivateKey{}
	return newPrivateKeyFromSeed(priv, seed)
}

func newPrivateKeyFromSeed(priv *PrivateKey, seed []byte) (*PrivateKey, error) {
	fips140.RecordApproved()
	if l := len(seed); l != seedSize {
		return nil, errors.New("ed25519: bad seed length: " + strconv.Itoa(l))
	}
	copy(priv.seed[:], seed)
	precomputePrivateKey(priv)
	return priv, nil
}

func precomputePrivateKey(priv *PrivateKey) {
	hs := sha512.New()
	hs.Write(priv.seed[:])
	h := hs.Sum(make([]byte, 0, sha512Size))

	s, err := priv.s.SetBytesWithClamping(h[:32])
	if err != nil {
		panic("ed25519: internal error: setting scalar failed")
	}
	A := (&edwards25519.Point{}).ScalarBaseMult(s)
	copy(priv.pub[:], A.Bytes())

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Supply exactly 32 raw bytes as the seed.
  2. If you have a hex string, hex-decode it first (hex.DecodeString) and check len==32 before calling.
  3. If you have a 64-byte Ed25519 private key, call NewPrivateKey (not FromSeed).

Example fix

// before
seed, _ := hex.DecodeString(seedHex) // wrong length
priv, err := ed25519.NewPrivateKeyFromSeed(seed)

// after
seed, err := hex.DecodeString(seedHex)
if err != nil { return err }
if len(seed) != 32 { return fmt.Errorf("seed must be 32 bytes, got %d", len(seed)) }
priv, err := ed25519.NewPrivateKeyFromSeed(seed)
Defensive patterns

Strategy: validation

Validate before calling

const ed25519SeedSize = 32
if len(seed) != ed25519SeedSize {
    return nil, fmt.Errorf("ed25519 seed must be %d bytes, got %d", ed25519SeedSize, len(seed))
}
return ed25519.NewPrivateKeyFromSeed(seed)

Try / catch

priv, err := ed25519.NewPrivateKeyFromSeed(seed)
if err != nil {
    if strings.Contains(err.Error(), "bad seed length") {
        return fmt.Errorf("rejecting seed of wrong length: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling fips140/ed25519.NewPrivateKeyFromSeed(seed) with a seed slice whose length is not 32 (e.g. 16, 64, base64-decoded to 44, hex string instead of bytes).

Common situations: Passing a hex- or base64-encoded seed without decoding; reusing an Ed25519 private-key blob (64 bytes) as the seed; truncated seed from a misconfigured KMS or env var; copying a 'seed' that is actually the SHA-512 expanded form.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/6efa88b2cc6e796e. Report an issue: GitHub.