Repository: denoland/deno
Pull request: fix(ext/node): DiffieHellman constructor behaviors

This PR fixes the constructor behaviors of `DiffieHellman`, `DiffieHellmanGroup`, and `ECDH` classes. These classes now can be constructed without new operator.

towards #29637 

Changed files:
filename: ext/node/polyfills/internal/crypto/diffiehellman.ts
patch: @@ -51,7 +51,21 @@ import type { BufferEncoding } from "ext:deno_node/_global.d.ts";
 
 const DH_GENERATOR = 2;
 
-export class DiffieHellman {
+export function DiffieHellman(
+  sizeOrKey: number | string | ArrayBufferView,
+  keyEncoding?: unknown,
+  generator?: unknown,
+  genEncoding?: unknown,
+) {
+  return new DiffieHellmanImpl(
+    sizeOrKey,
+    keyEncoding,
+    generator,
+    genEncoding,
+  );
+}
+
+export class DiffieHellmanImpl {
   verifyError!: number;
   #prime: Buffer;
   #primeLength: number;
@@ -1108,15 +1122,21 @@ const DH_GROUPS = {
   },
 };
 
-export class DiffieHellmanGroup {
+DiffieHellman.prototype = DiffieHellmanImpl.prototype;
+
+export function DiffieHellmanGroup(name: string) {
+  return new DiffieHellmanGroupImpl(name);
+}
+
+export class DiffieHellmanGroupImpl {
   verifyError!: number;
-  #diffiehellman: DiffieHellman;
+  #diffiehellman: DiffieHellmanImpl;
 
   constructor(name: string) {
     if (!DH_GROUP_NAMES.includes(name)) {
       throw new ERR_CRYPTO_UNKNOWN_DH_GROUP();
     }
-    this.#diffiehellman = new DiffieHellman(
+    this.#diffiehellman = new DiffieHellmanImpl(
       Buffer.from(DH_GROUPS[name].prime),
       DH_GROUPS[name].generator,
     );
@@ -1180,7 +1200,13 @@ export class DiffieHellmanGroup {
   }
 }
 
-export class ECDH {
+DiffieHellmanGroup.prototype = DiffieHellmanGroupImpl.prototype;
+
+export function ECDH(curve: string) {
+  return new ECDHImpl(curve);
+}
+
+export class ECDHImpl {
   #curve: EllipticCurve; // the selected curve
   #privbuf: Buffer; // the private key
   #pubbuf: Buffer; // the public key
@@ -1311,6 +1337,8 @@ export class ECDH {
   }
 }
 
+ECDH.prototype = ECDHImpl.prototype;
+
 export function diffieHellman(options: {
   privateKey: KeyObject;
   publicKey: KeyObject;

filename: tests/node_compat/config.jsonc
patch: @@ -384,6 +384,7 @@
       "test-console-sync-write-error.js",
       "test-console-table.js",
       "test-console-tty-colors.js",
+      "test-crypto-dh-constructor.js",
       "test-crypto-dh-errors.js",
       "test-crypto-dh-odd-key.js",
       "test-crypto-dh-shared.js",

filename: tests/node_compat/runner/TODO.md
patch: @@ -1,7 +1,7 @@
 <!-- deno-fmt-ignore-file -->
 # Remaining Node Tests
 
-1204 tests out of 3993 have been ported from Node 23.9.0 (30.15% ported, 70.47% remaining).
+1205 tests out of 3993 have been ported from Node 23.9.0 (30.18% ported, 70.45% remaining).
 
 NOTE: This file should not be manually edited. Please edit `tests/node_compat/config.json` and run `deno task setup` in `tests/node_compat/runner` dir instead.
 
@@ -494,7 +494,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
 - [parallel/test-crypto-cipheriv-decipheriv.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-cipheriv-decipheriv.js)
 - [parallel/test-crypto-classes.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-classes.js)
 - [parallel/test-crypto-des3-wrap.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-des3-wrap.js)
-- [parallel/test-crypto-dh-constructor.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-dh-constructor.js)
 - [parallel/test-crypto-dh-curves.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-dh-curves.js)
 - [parallel/test-crypto-dh-generate-keys.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-dh-generate-keys.js)
 - [parallel/test-crypto-dh-group-setters.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-crypto-dh-group-setters.js)

filename: tests/node_compat/test/parallel/test-crypto-dh-constructor.js
patch: @@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 23.9.0
+// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+const { hasOpenSSL3 } = require('../common/crypto');
+
+const size = crypto.getFips() || hasOpenSSL3 ? 1024 : 256;
+const dh1 = crypto.createDiffieHellman(size);
+const p1 = dh1.getPrime('buffer');
+
+{
+  const DiffieHellman = crypto.DiffieHellman;
+
+  const dh = DiffieHellman(p1, 'buffer');
+  assert(dh instanceof DiffieHellman, 'DiffieHellman is expected to return a ' +
+                                      'new instance when called without `new`');
+}
+
+{
+  const DiffieHellmanGroup = crypto.DiffieHellmanGroup;
+  const dhg = DiffieHellmanGroup('modp5');
+  assert(dhg instanceof DiffieHellmanGroup, 'DiffieHellmanGroup is expected ' +
+                                            'to return a new instance when ' +
+                                            'called without `new`');
+}
+
+{
+  const ECDH = crypto.ECDH;
+  const ecdh = ECDH('prime256v1');
+  assert(ecdh instanceof ECDH, 'ECDH is expected to return a new instance ' +
+                              'when called without `new`');
+}