{"record":{"id":"cc9df99ae108d4a2","repo":"denoland/deno","slug":"only-sha512-is-supported-for-ed25519-keys","errorCode":null,"errorMessage":"Only 'sha512' is supported for Ed25519 keys","messagePattern":"Only 'sha512' is supported for Ed25519 keys","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/sig.ts","lineNumber":411,"sourceCode":"  try {\n    const res = prepareAsymmetricKey(key, kConsumePrivate);\n    let handle;\n    if (ReflectHas(res, \"handle\")) {\n      handle = res.handle;\n    } else {\n      handle = op_node_create_private_key(\n        res.data,\n        res.format,\n        res.type ?? \"\",\n        res.passphrase,\n      );\n    }\n\n    let result: Buffer;\n    const keyType = op_node_get_asymmetric_key_type(handle);\n    if (keyType === \"ed25519\") {\n      if (algorithm != null && algorithm !== \"sha512\") {\n        throw new TypeError(\"Only 'sha512' is supported for Ed25519 keys\");\n      }\n      result = new FastBuffer(64);\n      op_node_sign_ed25519(handle, dataBytes, result);\n    } else if (keyType === \"ed448\") {\n      const keyOpts = typeof key === \"object\" && key !== null &&\n          !(ObjectPrototypeIsPrototypeOf(KeyObject.prototype, key))\n        ? key as Record<string, unknown>\n        : null;\n      const ctx = keyOpts?.context;\n      if (\n        ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, ctx) &&\n        ctx.length > 0\n      ) {\n        throw new TypeError(\"Context parameter is unsupported\");\n      }\n      result = new FastBuffer(114);\n      op_node_sign_ed448(handle, dataBytes, result);\n    } else {","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/sig.ts#L393-L429","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass null as the algorithm for ed25519 keys: crypto.sign(null, data, ed25519Key).","Branch on key.asymmetricKeyType: use null for \"ed25519\"/\"ed448\", the digest otherwise.","In JWT code, map EdDSA/OKP keys to digestless signing instead of RS/ES hashing."],"exampleFix":"// before\nconst sig = crypto.sign(\"sha256\", data, key); // throws when key is ed25519\n\n// after\nconst alg = key.asymmetricKeyType === \"ed25519\" ? null : \"sha256\";\nconst sig = crypto.sign(alg, data, key);","handlingStrategy":"validation","validationCode":"function digestArgFor(key, requested) {\n  const type = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;\n  if (type === \"ed25519\" || type === \"ed448\") return null;\n  if (requested != null) return requested;\n  throw new TypeError(\"digest required for this key type\");\n}\nconst sig = crypto.sign(digestArgFor(key, \"sha256\"), data, key);","typeGuard":"const isDigestlessKey = (key) => {\n  const t = key.asymmetricKeyType ?? key.key?.asymmetricKeyType;\n  return t === \"ed25519\" || t === \"ed448\";\n};","tryCatchPattern":"try {\n  sig = crypto.sign(alg, data, key);\n} catch (e) {\n  if (e instanceof TypeError && /Only 'sha512' is supported for Ed25519/.test(e.message)) {\n    throw new Error(\"pass null as the algorithm for ed25519 keys (SHA-512 is built in)\");\n  }\n  throw e;\n}","preventionTips":["Never hardcode a digest in shared signing helpers — derive it from key.asymmetricKeyType.","For JWTs, map alg headers: EdDSA -> null, RS256 -> sha256, ES384 -> sha384.","Only null or the literal \"sha512\" are valid for ed25519."],"tags":["crypto","ed25519","signing","algorithm-mismatch"],"backgroundTag":"ed25519-digest-mismatch","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}