denoland/deno · error · TypeError

Only 'sha512' is supported for Ed25519 keys

Error message

Only 'sha512' is supported for Ed25519 keys

What it means

Ed25519 signs the raw message with SHA-512 built into the algorithm, so there is no selectable digest. One-shot crypto.sign() only accepts algorithm === null/undefined or the literal "sha512" when the key type is ed25519; any other digest string throws this TypeError.

Source

Thrown at ext/node/polyfills/internal/crypto/sig.ts:411

  try {
    const res = prepareAsymmetricKey(key, kConsumePrivate);
    let handle;
    if (ReflectHas(res, "handle")) {
      handle = res.handle;
    } else {
      handle = op_node_create_private_key(
        res.data,
        res.format,
        res.type ?? "",
        res.passphrase,
      );
    }

    let result: Buffer;
    const keyType = op_node_get_asymmetric_key_type(handle);
    if (keyType === "ed25519") {
      if (algorithm != null && algorithm !== "sha512") {
        throw new TypeError("Only 'sha512' is supported for Ed25519 keys");
      }
      result = new FastBuffer(64);
      op_node_sign_ed25519(handle, dataBytes, result);
    } else if (keyType === "ed448") {
      const keyOpts = typeof key === "object" && key !== null &&
          !(ObjectPrototypeIsPrototypeOf(KeyObject.prototype, key))
        ? key as Record<string, unknown>
        : null;
      const ctx = keyOpts?.context;
      if (
        ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, ctx) &&
        ctx.length > 0
      ) {
        throw new TypeError("Context parameter is unsupported");
      }
      result = new FastBuffer(114);
      op_node_sign_ed448(handle, dataBytes, result);
    } else {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass null as the algorithm for ed25519 keys: crypto.sign(null, data, ed25519Key).
  2. Branch on key.asymmetricKeyType: use null for "ed25519"/"ed448", the digest otherwise.
  3. In JWT code, map EdDSA/OKP keys to digestless signing instead of RS/ES hashing.

Example fix

// before
const sig = crypto.sign("sha256", data, key); // throws when key is ed25519

// after
const alg = key.asymmetricKeyType === "ed25519" ? null : "sha256";
const sig = crypto.sign(alg, data, key);
Defensive patterns

Strategy: validation

Validate before calling

function digestArgFor(key, requested) {
  const type = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;
  if (type === "ed25519" || type === "ed448") return null;
  if (requested != null) return requested;
  throw new TypeError("digest required for this key type");
}
const sig = crypto.sign(digestArgFor(key, "sha256"), data, key);

Type guard

const isDigestlessKey = (key) => {
  const t = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;
  return t === "ed25519" || t === "ed448";
};

Try / catch

try {
  sig = crypto.sign(alg, data, key);
} catch (e) {
  if (e instanceof TypeError && /Only 'sha512' is supported for Ed25519/.test(e.message)) {
    throw new Error("pass null as the algorithm for ed25519 keys (SHA-512 is built in)");
  }
  throw e;
}

Prevention

When it happens

Trigger: crypto.sign("sha256", message, ed25519KeyObject); a generic signWith(algorithm, ...) helper with a hardcoded "sha256" applied to an ed25519 key; RFC 8032 keys generated by ssh-keygen or WebCrypto fed into RSA-era signing code.

Common situations: Migrating an RSA or ECDSA signing path to ed25519 while keeping the digest argument; JWT/JOSE libraries where RS256-era code calls one-shot sign with a fixed hash; key-agnostic utility functions that always pass a digest.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/cc9df99ae108d4a2. Report an issue: GitHub.