{"record":{"id":"1113fc69b7c19e72","repo":"denoland/deno","slug":"private-key-is-not-valid-for-specified-curve","errorCode":null,"errorMessage":"Private key is not valid for specified curve","messagePattern":"Private key is not valid for specified curve","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/diffiehellman.ts","lineNumber":1557,"sourceCode":"      pubbuf[0] = compressedBuf[0] + 4;\n    }\n    return ecdhEncode(pubbuf, encoding ?? \"buffer\");\n  }\n\n  setPrivateKey(\n    privateKey: ArrayBufferView | string,\n    encoding?: any,\n  ): Buffer | string {\n    let privbuf: Buffer;\n    if (typeof privateKey === \"string\") {\n      privbuf = Buffer.from(privateKey, encoding);\n    } else {\n      const parts = getViewParts(privateKey);\n      privbuf = Buffer.from(parts.ab, parts.off, parts.len);\n    }\n\n    if (!op_node_ecdh_validate_private_key(this.#curve.name, privbuf)) {\n      throw new Error(\"Private key is not valid for specified curve\");\n    }\n\n    const pubbuf = Buffer.alloc(this.#curve.publicKeySize);\n    op_node_ecdh_compute_public_key(this.#curve.name, privbuf, pubbuf);\n\n    this.#privbuf = privbuf;\n    this.#pubbuf = pubbuf;\n\n    return pubbuf;\n  }\n\n  setPublicKey(\n    publicKey: ArrayBufferView | string,\n    encoding?: any,\n  ): void {\n    let pubbuf: Buffer;\n    if (typeof publicKey === \"string\") {\n      pubbuf = Buffer.from(publicKey, encoding);","sourceCodeStart":1539,"sourceCodeEnd":1575,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/diffiehellman.ts#L1539-L1575","documentation":"setPrivateKey() validates the supplied bytes with op_node_ecdh_validate_private_key and throws this Error when they are not a legal private scalar for the curve: wrong byte length, an all-zero value, or a value at or above the curve order. The polyfill matches Node's behavior of rejecting the import rather than storing a unusable key.","triggerScenarios":"ecdh.setPrivateKey(buf) where buf has the wrong size for the curve (e.g. 30 or 64 bytes for P-256, which expects 32), is zero, or >= n; passing the public key by mistake; decoding a hex private key string without the 'hex' encoding so it becomes 64 utf8 bytes.","commonSituations":"Reading a stored hex key with Buffer.from(key) instead of Buffer.from(key, 'hex'); interoperating with systems that pad or strip leading zero bytes inconsistently; copying a secp256k1 key into a P-256 instance (both 32 bytes, but the value can exceed P-256's order).","solutions":["Match the byte length to the curve: P-256/X25519/secp256k1: 32; P-384: 48; P-521: 66","Decode hex/base64 strings with the explicit encoding: Buffer.from(privHex, 'hex')","Left-pad or right-trim with 0x00 to the exact field size if the key came from a system that drops leading zeros","Confirm you are importing the private scalar, not the public key or a DER wrapper (unwrap DER first)"],"exampleFix":"// before\necdh.setPrivateKey(Buffer.from(privHex)); // utf8 bytes of hex text -> wrong length\n\n// after\necdh.setPrivateKey(Buffer.from(privHex, 'hex')); // 32 bytes for P-256","handlingStrategy":"validation","validationCode":"const PRIV_LEN = { prime256v1: 32, secp384r1: 48, secp521r1: 66, X25519: 32 }[curve]!;\nif (privBuf.length !== PRIV_LEN || privBuf.every((b) => b === 0)) {\n  throw new RangeError(`private key must be ${PRIV_LEN} non-zero bytes for ${curve}`);\n}\necdh.setPrivateKey(privBuf);","typeGuard":"const isCurvePrivateScalar = (b: Uint8Array, curve: string): boolean => {\n  const sizes: Record<string, number> = { prime256v1: 32, secp384r1: 48, secp521r1: 66, X25519: 32 };\n  return b.length === sizes[curve] && b.some((x) => x !== 0);\n};","tryCatchPattern":"catch (e) { if (e.message === 'Private key is not valid for specified curve') { /* check encoding + length of stored key */ } throw e; }","preventionTips":["Always decode stored keys with an explicit encoding: Buffer.from(hex, 'hex')","Left-pad stored scalars that had leading zero bytes stripped","Validate key length against the curve constant in your key-import module"],"tags":["crypto","ecdh","private-key","validation"],"backgroundTag":"ecdh-invalid-private-key","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"}